博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Handler中post 方法的调用流程和使用场景
阅读量:5093 次
发布时间:2019-06-13

本文共 5779 字,大约阅读时间需要 19 分钟。

来自:http://blog.csdn.net/panjidong_3/article/details/7890383

感谢原作者。

====================================================================================

最近公司项目做了一些比较大的重构,很多地方都用了Handler.post(Runnable r),这个方法,比如这一段

  1. Handler mHandler = new Handler();  
  2. mHandler.post(new Runnable() {  
  3.     @Override  
  4.     public void run() {  
  5.         showContentView(contentView);  
Handler mHandler = new Handler();mHandler.post(new Runnable() {	@Override	public void run() {		showContentView(contentView);}});
下面我们先来看一下这个方法是怎么执行的
首先:
  1. public final boolean post(Runnable r)  
  2.     return  sendMessageDelayed(getPostMessage(r), 0);  
public final boolean post(Runnable r){    return  sendMessageDelayed(getPostMessage(r), 0);}
它把Runnable重新封装了一遍然后调用了sendMessageDelayed方法
看一下是怎么封装的
  1. private final Message getPostMessage(Runnable r) {  
  2.     Message m = Message.obtain();  
  3.     m.callback = r;  
  4.     return m;  
private final Message getPostMessage(Runnable r) {        Message m = Message.obtain();        m.callback = r;        return m;    }
看到了吧,用过Handler的都知道Message是用来记录信息的最小单元,这里把Runnable封装到一个Message对象并返回
然后:
  1. public final boolean sendMessageDelayed(Message msg, long delayMillis)  
  2.     if (delayMillis < 0) {  
  3.         delayMillis = 0;  
  4.     return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
public final boolean sendMessageDelayed(Message msg, long delayMillis)    {        if (delayMillis < 0) {            delayMillis = 0;        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    }
这里就是对delayMillis做了一下有效性检测
紧接着:
  1. public boolean sendMessageAtTime(Message msg, long uptimeMillis)  
  2.         boolean sent = false;  
  3.         MessageQueue queue = mQueue;  
  4.         if (queue != null) {  
  5.             msg.target = this;  
  6.             sent = queue.enqueueMessage(msg, uptimeMillis);  
  7.         else {  
  8.             RuntimeException e = new RuntimeException(  
  9.                 this + " sendMessageAtTime() called with no mQueue");  
  10.             Log.w("Looper", e.getMessage(), e);  
  11.         return sent;  
public boolean sendMessageAtTime(Message msg, long uptimeMillis)    {        boolean sent = false;        MessageQueue queue = mQueue;        if (queue != null) {            msg.target = this;            sent = queue.enqueueMessage(msg, uptimeMillis);        }        else {            RuntimeException e = new RuntimeException(                this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);        }        return sent;    }
Handler对象把Message压到了MessageQueue队列里面
貌似方法到这里就return了,那么压进去的信息是怎么发送的呢? 这得从Handler的原理说起了
有很多人已经写了这个原理了,就不在做阐述
可以查看这篇博客
然后我们去分发信息的点去看是如何执行的
  1. public static final void loop() {  
  2.         Looper me = myLooper();  
  3.         MessageQueue queue = me.mQueue;  
  4.         while (true) {  
  5.             Message msg = queue.next(); // might block  
  6.             //if (!me.mRun) {  
  7.             //    break;  
  8.             if (msg != null) {  
  9.                 if (msg.target == null) {  
  10.                     // No target is a magic identifier for the quit message.  
  11.                     return;  
  12.                 if (me.mLogging!= null) me.mLogging.println(  
  13.                         ">>>>> Dispatching to " + msg.target + " "  
  14.                         + msg.callback + ": " + msg.what  
  15.                 msg.target.dispatchMessage(msg);  
  16.                 if (me.mLogging!= null) me.mLogging.println(  
  17.                         "<<<<< Finished to    " + msg.target + " "  
  18.                         + msg.callback);  
  19.                 msg.recycle();  
public static final void loop() {        Looper me = myLooper();        MessageQueue queue = me.mQueue;        while (true) {            Message msg = queue.next(); // might block            //if (!me.mRun) {            //    break;            //}            if (msg != null) {                if (msg.target == null) {                    // No target is a magic identifier for the quit message.                    return;                }                if (me.mLogging!= null) me.mLogging.println(                        ">>>>> Dispatching to " + msg.target + " "                        + msg.callback + ": " + msg.what                        );                msg.target.dispatchMessage(msg);                if (me.mLogging!= null) me.mLogging.println(                        "<<<<< Finished to    " + msg.target + " "                        + msg.callback);                msg.recycle();            }        }    }
Looper对象把MessageQueue里面的Message逐个取出来,注意看msg.target.dispatchMessage(msg)这一句
Message类定义了一个字段target,这个字段就是Handler类型,存的对象就是创建这个message的对象,也就是我们的handler对象

然后就是调用我们的handler里面的dispatchMessage(msg)方法了

  1. public void dispatchMessage(Message msg) {  
  2.     if (msg.callback != null) {  
  3.         handleCallback(msg);  
  4.     } else {  
  5.         if (mCallback != null) {  
  6.             if (mCallback.handleMessage(msg)) {  
  7.                 return;  
  8.         handleMessage(msg);  
public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }
看到没有,一开始我们的Runnable传进来,然后调用GetPostMessage方法把Runnable赋值给了Massage里面的callback,
在分发的时候判断如果callback不是null就调用handleCallback(msg)方法
最后,执行我们的线程
  1. private final void handleCallback(Message message) {  
  2.     message.callback.run();  
private final void handleCallback(Message message) {        message.callback.run();    }
---------------------------------------------------------小小分割线----------------------------------------------------------
意义:
到了这里,我们发现貌似这玩意也就是转了一圈又调用了线程的run而已么,那么这又有什么用呢
如果我们给handler传入的是一个message,那么最后会调用我们的handler的handleMessage(Message)方法,然后我们再去判断最后再去处理
,但是我们用runnable可以直接传入如何操作的对象,不需要再接收到消息后再去判断message的what然后选择做什么操作,从代码清晰的角度,
我也觉得这样子会比在判断一遍要清晰,容易理解很多
---------------------------------------------------------小小分割线----------------------------------------------------------
所解决的问题:
请看博文第一段代码,这里面的runnable执行了一个setContentView(View),这里的handler是在onActivityResult里面调用的,也就是注销后重新登录回到主页面的这种情况,这个view里面包含了一些fragment,然后activity里面绑定fragment是需要是活动状态的,如果不用handler,直接执行,在onActivityResult方法执行期间activity还是在onPause状态,所以在程序执行到添加fragment的时候报错了,而用了handler就能保证这段代码最后会在activity处于活动状态既UI线程里面执行了
 
 
 
 
 
 

转载于:https://www.cnblogs.com/elefish/archive/2013/01/31/2888154.html

你可能感兴趣的文章
点火开关分为4个档位,分别是off,acc,IG-on,和ST
查看>>
RDLC报表上下标实现
查看>>
我的代码库-Java8实现FTP与SFTP文件上传下载
查看>>
js 原型链的介绍
查看>>
MVC Ajax
查看>>
PHP精粹:编写高效PHP代码(资深PHP技术专家多……
查看>>
MfgTool (i.MX53)使用
查看>>
125. Valid Palindrome java solutions
查看>>
[bzoj3217]ALOEXT
查看>>
Python学习笔记五
查看>>
Linux性能优化之内存优化(二)
查看>>
entity framework 数据库默认时间的问题的一种解决方案
查看>>
CAN总线
查看>>
WCF基本应用
查看>>
{暴力}
查看>>
Dropbox推荐使用
查看>>
第k个素数
查看>>
element-UI中table表格的row-click事件怎么获取一行数据的id
查看>>
程序员技术练级攻略
查看>>
导出数据报ORA-39002: 操作无效 ORA-39070: 无法打开日志文件。 ORA-39087: 目录名 DUMP_DIR 无效...
查看>>