Handler详解系列(五)——Handler的post()方法详解

MainActivity如下:

package cc.testui1;

import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.app.Activity;
/**
 * Demo描述:
 * 在子线程中更改UI的方式一
 * 
 * 在子线程中利用主线程的Handler的post()方法
 * 更改UI这个在子线程中sendMessage()原理和形式都很类似.
 * 
 * 详细分析:
 * 在Handler调用其post()方法时,方法的调用顺序如下:
 * Handler的post()方法--->Handler的sendMessageDelayed()方法--->
 * Handler的sendMessageAtTime()方法.
 * 至此又回到了前面熟悉的sendMessageAtTime()
 * 
 * 详细的代码如下:
 * public final boolean post(Runnable r){
 *    return  sendMessageDelayed(getPostMessage(r), 0);
 * }
 * 
 * 
 * private final Message getPostMessage(Runnable r) {
 *    Message m = Message.obtain();
 *    m.callback = r;
 *    return m;
 * }
 * 
 * 
 * public final boolean sendMessageDelayed(Message msg, long delayMillis){
 *   if (delayMillis < 0) {
 *       delayMillis = 0;
 *      }
 *   return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
 * }
 * 
 * 
 * 在这个详细的过程中可以看到在post(Runnable r)中利用该方法的输入参数r调用了getPostMessage(r)
 * 将r封装成了一个Message.
 * 重点是getPostMessage(r)方法中的 m.callback = r
 * 将r赋值给了Message的callback!!!!!
 * 
 * 回顾一下出队时调用的dispatchMessage()方法
 * 下面接着看Handler的dispatchMessage(Message msg)方法:
 *  public void dispatchMessage(Message msg) {
 *       //1 message的callback
 *    if (msg.callback != null) {
 *       handleCallback(msg);
 *    } else {
 *       //2 handler的callback
 *       if (mCallback != null) {
 *           if (mCallback.handleMessage(msg)) {
 *               return;
 *          }
 *      }
 *      //3 Handler的handleMessage()
 *      handleMessage(msg);
 *    }
 *  }
 * 
 * 
 * 在1处就判断出该Message的callback不为null,于是调用 handleCallback(msg);
 * 详细代码如下:
 * private static void handleCallback(Message message) {
 *   message.callback.run();
 * }
 * 该方法比较简单:就是直接调用post(Runnable r)的输入参数(Runnable对象)的run()方法.
 * 
 * 小结:
 * 1 在子线程中利用post(Runnable r)更新UI,原理和sendMessage()类似.
 * 2 注意:
 *   在下面的示例中mHandler是主线程的Handler.
 *   所以“在子线程中利用post(Runnable r)更新UI”这个说法不是特别准确.
 *   确切地说还是在子线程中发送了消息到主线程的消息队列从而更新了UI.
 * 3 调用post(Runnable r)不会开启一个新的线程,UI的更新是在主线程中完成的!!!!!!!!!!!!!!
 *   在下面的示例中可在两个地方输出线程ID发现两个值是一样的.
 *   所以在post方法中勿做耗时操作!!!!!!!!!!!!!!!!!!!!!!!
 * 4 其实在第一次看到“message.callback.run().....调用post(Runnable r)不会开启一个新的线程,UI更新是在主线程中完成的....”
 *   时,脑子里发热有点晕:既然都调用run()方法了,还不会开启线程???
 *   哎,这是平常看多了线程Thread和它里面的run()方法带来的误解.
 *   当然Thread调用start()是会开启一个线程的,这个毋庸置疑.
 *   但是如下:
 *   Runnable runnable=new Runnable() {
 *       @Override
 *       public void run() {
 *             System.out.println("Runnable中线程ID:"+Thread.currentThread().getId());
 *            }
 *   };
 *   runnable.run();
 *   它会在一个新线程中运行么?当然不会,直观地说就是它还没有和Thread任何关系.
 *   这么写的话此处的runnable只是一个Runnable接口实现类的对象而已,且该对象调用了方法run().
 *   此时就和一个普通的Object类对象object调用method没啥区别了.
 *   
 * 
 * 
 * 参考资料:
 * 1 http://www.jb51.net/article/37465.htm
 * 2 http://www.eoeandroid.com/blog-660972-48541.html
 * 3 https://software.intel.com/zh-cn/blogs/2010/09/15/start-run
 *   Thank you very much
 *
 */
public class MainActivity extends Activity {
    private TextView mTextView;
    private Handler mHandler;
    private Button mButton;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		init();
	}
    private void init(){
    	mHandler=new Handler();
    	mTextView=(TextView) findViewById(R.id.textView);
    	mButton=(Button) findViewById(R.id.button);
    	mButton.setOnClickListener(new OnClickListenerImpl());
    	System.out.println("UI线程ID="+Thread.currentThread().getId());
    }
    
  
    private class OnClickListenerImpl implements OnClickListener{
		@Override
		public void onClick(View v) {
			new Thread(){
	    		public void run() {
	    			mHandler.post(new Runnable() {
						@Override
						public void run() {
							System.out.println("post(Runnable r)里的run()方法中线程ID="+Thread.currentThread().getId());
							mTextView.setText("My number is 007");
						}
					});
	    		};
	    	}.start();
			
		}
    	
    }
	
}




main.xml如下:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
   >

     <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="test"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="50dip"
        />
     
     <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Button"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="120dip"
        />
    
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="测试在子线程中更新UI" 
        android:layout_centerInParent="true"
        />

</RelativeLayout>


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谷哥的小弟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值