Handler post(Runnable runnable)和sendMessage(Message msg)的区别比较

先上Handler的源码看一下:

[java]  view plain  copy
  1. /** 
  2.      * Default constructor associates this handler with the {@link Looper} for the 
  3.      * current thread. 
  4.      * 
  5.      * If this thread does not have a looper, this handler won't be able to receive messages 
  6.      * so an exception is thrown. 
  7.      */  
  8.     public Handler() {  
  9.         this(nullfalse);  
  10.     }  
  11.   
  12.     /** 
  13.      * Constructor associates this handler with the {@link Looper} for the 
  14.      * current thread and takes a callback interface in which you can handle 
  15.      * messages. 
  16.      * 
  17.      * If this thread does not have a looper, this handler won't be able to receive messages 
  18.      * so an exception is thrown. 
  19.      * 
  20.      * @param callback The callback interface in which to handle messages, or null. 
  21.      */  
  22.     public Handler(Callback callback) {  
  23.         this(callback, false);  
  24.     }  
  25.   
  26.     /** 
  27.      * Use the provided {@link Looper} instead of the default one. 
  28.      * 
  29.      * @param looper The looper, must not be null. 
  30.      */  
  31.     public Handler(Looper looper) {  
  32.         this(looper, nullfalse);  
  33.     }  
  34.   
  35.     /** 
  36.      * Use the provided {@link Looper} instead of the default one and take a callback 
  37.      * interface in which to handle messages. 
  38.      * 
  39.      * @param looper The looper, must not be null. 
  40.      * @param callback The callback interface in which to handle messages, or null. 
  41.      */  
  42.     public Handler(Looper looper, Callback callback) {  
  43.         this(looper, callback, false);  
  44.     }  
  45.   
  46.     /** 
  47.      * Use the {@link Looper} for the current thread 
  48.      * and set whether the handler should be asynchronous. 
  49.      * 
  50.      * Handlers are synchronous by default unless this constructor is used to make 
  51.      * one that is strictly asynchronous. 
  52.      * 
  53.      * Asynchronous messages represent interrupts or events that do not require global ordering 
  54.      * with respect to synchronous messages.  Asynchronous messages are not subject to 
  55.      * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. 
  56.      * 
  57.      * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for 
  58.      * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. 
  59.      * 
  60.      * @hide 
  61.      */  
  62.     public Handler(boolean async) {  
  63.         this(null, async);  
  64.     }  
  65.   
  66.     /** 
  67.      * Use the {@link Looper} for the current thread with the specified callback interface 
  68.      * and set whether the handler should be asynchronous. 
  69.      * 
  70.      * Handlers are synchronous by default unless this constructor is used to make 
  71.      * one that is strictly asynchronous. 
  72.      * 
  73.      * Asynchronous messages represent interrupts or events that do not require global ordering 
  74.      * with respect to synchronous messages.  Asynchronous messages are not subject to 
  75.      * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. 
  76.      * 
  77.      * @param callback The callback interface in which to handle messages, or null. 
  78.      * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for 
  79.      * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. 
  80.      * 
  81.      * @hide 
  82.      */  
  83.     public Handler(Callback callback, boolean async) {  
  84.         if (FIND_POTENTIAL_LEAKS) {  
  85.             final Class<? extends Handler> klass = getClass();  
  86.             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&  
  87.                     (klass.getModifiers() & Modifier.STATIC) == 0) {  
  88.                 Log.w(TAG, "The following Handler class should be static or leaks might occur: " +  
  89.                     klass.getCanonicalName());  
  90.             }  
  91.         }  
  92.   
  93.         mLooper = Looper.myLooper();  
  94.         if (mLooper == null) {  
  95.             throw new RuntimeException(  
  96.                 "Can't create handler inside thread that has not called Looper.prepare()");  
  97.         }  
  98.         mQueue = mLooper.mQueue;  
  99.         mCallback = callback;  
  100.         mAsynchronous = async;  
  101.     }  
  102.   
  103.     /** 
  104.      * Use the provided {@link Looper} instead of the default one and take a callback 
  105.      * interface in which to handle messages.  Also set whether the handler 
  106.      * should be asynchronous. 
  107.      * 
  108.      * Handlers are synchronous by default unless this constructor is used to make 
  109.      * one that is strictly asynchronous. 
  110.      * 
  111.      * Asynchronous messages represent interrupts or events that do not require global ordering 
  112.      * with respect to synchronous messages.  Asynchronous messages are not subject to 
  113.      * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}. 
  114.      * 
  115.      * @param looper The looper, must not be null. 
  116.      * @param callback The callback interface in which to handle messages, or null. 
  117.      * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for 
  118.      * each {@link Message} that is sent to it or {@link Runnable} that is posted to it. 
  119.      * 
  120.      * @hide 
  121.      */  
  122.     public Handler(Looper looper, Callback callback, boolean async) {  
  123.         mLooper = looper;  
  124.         mQueue = looper.mQueue;  
  125.         mCallback = callback;  
  126.         mAsynchronous = async;  
  127.     }  

无聊的源码copy,可以看到最终都是调用的最后一个构造函数,Android源码里面到处都是这种写法,接下来我们要讲的sendMessage也是这种写法。这样写的好处是,我们不用关心过多的参数,灵活适配各种不同的需求。来看下初始化的三个属性,Looper:上面有说,Handler与创建它的线程的消息队列是绑定的,实际上Handler收发消息的三要素Handler、MessageQueue、Looper,是缺一不可的,线程必须有Looper,才能从MessageQueue里把消息取出来,所以一定要创建Looper才能使用Handler,刚刚的例子我们并没有看到Looper创建,而我们之所以能够在Activity里直接使用Handler是因为主线程,也叫UI线程、ActivityThread被创建的时候会初始化一个Looper。所以我们能够在UI线程里直接使用Looper(因为更新UI使用的多,而且Android整个窗口的UI更新都是用的Handler机制)。Callback:接口,回调用来写收到消息后处理消息的代码。async:传给消息的一个boolean型变量,是否需要同步。

直接来看我们最熟悉的sendMessage的方法:

[java]  view plain  copy
  1. public final boolean sendMessage(Message msg)  
  2.  {  
  3.      return sendMessageDelayed(msg, 0);  
  4.  }  

最普通的发送消息,其内部使用了延时发送,延时设为0. 这是Android里面常用的模式,这样做的好处是当你不需要传参数的时候可以直接使用无参的,使用方便,而且内部减少

了代码量,避免再重复写一个发送消息的实现。

   

[java]  view plain  copy
  1. /** 
  2.      * Sends a Message containing only the what value. 
  3.      *   
  4.      * @return Returns true if the message was successfully placed in to the  
  5.      *         message queue.  Returns false on failure, usually because the 
  6.      *         looper processing the message queue is exiting. 
  7.      */  
  8.     public final boolean sendEmptyMessage(int what)  
  9.     {  
  10.         return sendEmptyMessageDelayed(what, 0);  
  11.     }  

发送一个空消息只需要传递一个信号,用消息类型就足够携带我们要传递的信息。同样调用了它的延时发送方法,延时为0.

[java]  view plain  copy
  1. /** 
  2.  * Sends a Message containing only the what value, to be delivered 
  3.  * after the specified amount of time elapses. 
  4.  * @see #sendMessageDelayed(android.os.Message, long)  
  5.  *  
  6.  * @return Returns true if the message was successfully placed in to the  
  7.  *         message queue.  Returns false on failure, usually because the 
  8.  *         looper processing the message queue is exiting. 
  9.  */  
  10. public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {  
  11.     Message msg = Message.obtain();  
  12.     msg.what = what;  
  13.     return sendMessageDelayed(msg, delayMillis);  
  14. }  

我们可以看到,系统同样是通过发送Message对象来实现的发送空消息。这个对象值承载了我们设置的What信息。它最终调的也是 sendMessageDelayed(msg, delayMillis);延时发送一个消息。这里用了 Message.obtain();这是一种单例模式,避免每发送一个消息就new出一个对象,如果这样内存占用会很高,而且没有必要。在讲Message的时候会讲到。

 

[java]  view plain  copy
  1. /** 
  2.   * Sends a Message containing only the what value, to be delivered  
  3.   * at a specific time. 
  4.   * @see #sendMessageAtTime(android.os.Message, long) 
  5.   *   
  6.   * @return Returns true if the message was successfully placed in to the  
  7.   *         message queue.  Returns false on failure, usually because the 
  8.   *         looper processing the message queue is exiting. 
  9.   */  
  10.  public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {  
  11.      Message msg = Message.obtain();  
  12.      msg.what = what;  
  13.      return sendMessageAtTime(msg, uptimeMillis);  
  14.  }  

这是一个定时在某个确定的时刻发送空消息的方法,内部同样调用了发送消息对应的方法。如果我们猜想的话,这个确定时刻发送同样可以用延时发送消息的方法来实现,只需要计算确定的那个时刻和当前时间的差值,然后把这个差值设为延时参数即可。后面来验证我们的猜想是否正确。

[java]  view plain  copy
  1. /** 
  2.      * Enqueue a message into the message queue after all pending messages 
  3.      * before (current time + delayMillis). You will receive it in 
  4.      * {@link #handleMessage}, in the thread attached to this handler. 
  5.      *   
  6.      * @return Returns true if the message was successfully placed in to the  
  7.      *         message queue.  Returns false on failure, usually because the 
  8.      *         looper processing the message queue is exiting.  Note that a 
  9.      *         result of true does not mean the message will be processed -- if 
  10.      *         the looper is quit before the delivery time of the message 
  11.      *         occurs then the message will be dropped. 
  12.      */  
  13.     public final boolean sendMessageDelayed(Message msg, long delayMillis)  
  14.     {  
  15.         if (delayMillis < 0) {  
  16.             delayMillis = 0;  
  17.         }  
  18.         return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);  
  19.     }  

看了这个方法,我们突然有一种被耍的赶脚,原来不是定时发送调了延时发送,而是延时发送内部调了定时发送,哈哈,这样也可以解释,因为他们本身就可以通过当前时间相互来转化。这里把当前时间加上延时时间,来计算要发送消息的时刻,最终用定时发送来实现。

[java]  view plain  copy
  1. /** 
  2.     * Enqueue a message into the message queue after all pending messages 
  3.     * before the absolute time (in milliseconds) <var>uptimeMillis</var>. 
  4.     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 
  5.     * Time spent in deep sleep will add an additional delay to execution. 
  6.     * You will receive it in {@link #handleMessage}, in the thread attached 
  7.     * to this handler. 
  8.     *  
  9.     * @param uptimeMillis The absolute time at which the message should be 
  10.     *         delivered, using the 
  11.     *         {@link android.os.SystemClock#uptimeMillis} time-base. 
  12.     *          
  13.     * @return Returns true if the message was successfully placed in to the  
  14.     *         message queue.  Returns false on failure, usually because the 
  15.     *         looper processing the message queue is exiting.  Note that a 
  16.     *         result of true does not mean the message will be processed -- if 
  17.     *         the looper is quit before the delivery time of the message 
  18.     *         occurs then the message will be dropped. 
  19.     */  
  20.    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {  
  21.        MessageQueue queue = mQueue;  
  22.        if (queue == null) {  
  23.            RuntimeException e = new RuntimeException(  
  24.                    this + " sendMessageAtTime() called with no mQueue");  
  25.            Log.w("Looper", e.getMessage(), e);  
  26.            return false;  
  27.        }  
  28.        return enqueueMessage(queue, msg, uptimeMillis);  
  29.    }  

可以看到这个才是真正的发送了一条消息的方法,上面的所有发送消息的方法最终都是要调这个方法。在发送消息的最后又调用了这个enqueueMessage(queue, msg, uptimeMillis);从名字看,我们大概可以猜到,这里应该是把消息和消息确切的发送时间,塞到消息队列里面。稍有开发经验的都知道,把消息塞给队列这种事理论上应该交个MessageQueue来提供一个方法比较合理,Android为什么这么搞呢?我们带着这个疑问来看Handler提供的这个方法:

[java]  view plain  copy
  1. private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  
  2.        msg.target = this;  
  3.        if (mAsynchronous) {  
  4.            msg.setAsynchronous(true);  
  5.        }  
  6.        return queue.enqueueMessage(msg, uptimeMillis);  
  7.    }  

这里可以看到这里这个方法并没有做什么事,只是给Message的target属性赋值,表示这个消息的接收者是自己,这不就是Handler自己发消息给自己的判断标识么。。。mAsynchronous这个值是表示是否是同步的,是在Handler构造方法里传进来的。最后又把这个属性塞给了Message,让Message自己处理是否同步的问题。后面调了MessageQueue的enqueueMessage方法,到这里Handler消息的发送过程也就结束了。(多说一句,这里传的时间,其实是用来排序的,Message里面有一个long型的属性when,就是Message的时间标签,最终这里传入的uptimeillis会赋值给msg的when属性,让MessageQueue用来根据时间对所有插入Message进行排队,构成一个单链表。存放消息和循环用。为什么用链表,数据不停的再插入删除什么的操作,所以用链表,Android真屌,我平时都注意不到这些小细节,自己上去就乱搞。在MessageQueue的源码里可以看到这个过程,这里就不再讲述了,因为我们平常也不和MessageQueue直接打交道)

[java]  view plain  copy
  1. /** 
  2.     * Enqueue a message at the front of the message queue, to be processed on 
  3.     * the next iteration of the message loop.  You will receive it in 
  4.     * {@link #handleMessage}, in the thread attached to this handler. 
  5.     * <b>This method is only for use in very special circumstances -- it 
  6.     * can easily starve the message queue, cause ordering problems, or have 
  7.     * other unexpected side-effects.</b> 
  8.     *   
  9.     * @return Returns true if the message was successfully placed in to the  
  10.     *         message queue.  Returns false on failure, usually because the 
  11.     *         looper processing the message queue is exiting. 
  12.     */  
  13.    public final boolean sendMessageAtFrontOfQueue(Message msg) {  
  14.        MessageQueue queue = mQueue;  
  15.        if (queue == null) {  
  16.            RuntimeException e = new RuntimeException(  
  17.                this + " sendMessageAtTime() called with no mQueue");  
  18.            Log.w("Looper", e.getMessage(), e);  
  19.            return false;  
  20.        }  
  21.        return enqueueMessage(queue, msg, 0);  
  22.    }  

和这个和上面的方法基本一样就是设置了时间为0,表示在排队时把它塞到队列的最前端。不多讲了。

postRunnable的所有方法:

[java]  view plain  copy
  1. /** 
  2.      * Causes the Runnable r to be added to the message queue. 
  3.      * The runnable will be run on the thread to which this handler is  
  4.      * attached.  
  5.      *   
  6.      * @param r The Runnable that will be executed. 
  7.      *  
  8.      * @return Returns true if the Runnable was successfully placed in to the  
  9.      *         message queue.  Returns false on failure, usually because the 
  10.      *         looper processing the message queue is exiting. 
  11.      */  
  12.     public final boolean post(Runnable r)  
  13.     {  
  14.        return  sendMessageDelayed(getPostMessage(r), 0);  
  15.     }  
  16.   
  17.     /** 
  18.      * Causes the Runnable r to be added to the message queue, to be run 
  19.      * at a specific time given by <var>uptimeMillis</var>. 
  20.      * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 
  21.      * Time spent in deep sleep will add an additional delay to execution. 
  22.      * The runnable will be run on the thread to which this handler is attached. 
  23.      * 
  24.      * @param r The Runnable that will be executed. 
  25.      * @param uptimeMillis The absolute time at which the callback should run, 
  26.      *         using the {@link android.os.SystemClock#uptimeMillis} time-base. 
  27.      *   
  28.      * @return Returns true if the Runnable was successfully placed in to the  
  29.      *         message queue.  Returns false on failure, usually because the 
  30.      *         looper processing the message queue is exiting.  Note that a 
  31.      *         result of true does not mean the Runnable will be processed -- if 
  32.      *         the looper is quit before the delivery time of the message 
  33.      *         occurs then the message will be dropped. 
  34.      */  
  35.     public final boolean postAtTime(Runnable r, long uptimeMillis)  
  36.     {  
  37.         return sendMessageAtTime(getPostMessage(r), uptimeMillis);  
  38.     }  
  39.   
  40.     /** 
  41.      * Causes the Runnable r to be added to the message queue, to be run 
  42.      * at a specific time given by <var>uptimeMillis</var>. 
  43.      * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 
  44.      * Time spent in deep sleep will add an additional delay to execution. 
  45.      * The runnable will be run on the thread to which this handler is attached. 
  46.      * 
  47.      * @param r The Runnable that will be executed. 
  48.      * @param uptimeMillis The absolute time at which the callback should run, 
  49.      *         using the {@link android.os.SystemClock#uptimeMillis} time-base. 
  50.      *  
  51.      * @return Returns true if the Runnable was successfully placed in to the  
  52.      *         message queue.  Returns false on failure, usually because the 
  53.      *         looper processing the message queue is exiting.  Note that a 
  54.      *         result of true does not mean the Runnable will be processed -- if 
  55.      *         the looper is quit before the delivery time of the message 
  56.      *         occurs then the message will be dropped. 
  57.      *          
  58.      * @see android.os.SystemClock#uptimeMillis 
  59.      */  
  60.     public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)  
  61.     {  
  62.         return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);  
  63.     }  
  64.   
  65.     /** 
  66.      * Causes the Runnable r to be added to the message queue, to be run 
  67.      * after the specified amount of time elapses. 
  68.      * The runnable will be run on the thread to which this handler 
  69.      * is attached. 
  70.      * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b> 
  71.      * Time spent in deep sleep will add an additional delay to execution. 
  72.      *   
  73.      * @param r The Runnable that will be executed. 
  74.      * @param delayMillis The delay (in milliseconds) until the Runnable 
  75.      *        will be executed. 
  76.      *         
  77.      * @return Returns true if the Runnable was successfully placed in to the  
  78.      *         message queue.  Returns false on failure, usually because the 
  79.      *         looper processing the message queue is exiting.  Note that a 
  80.      *         result of true does not mean the Runnable will be processed -- 
  81.      *         if the looper is quit before the delivery time of the message 
  82.      *         occurs then the message will be dropped. 
  83.      */  
  84.     public final boolean postDelayed(Runnable r, long delayMillis)  
  85.     {  
  86.         return sendMessageDelayed(getPostMessage(r), delayMillis);  
  87.     }  
  88.   
  89.     /** 
  90.      * Posts a message to an object that implements Runnable. 
  91.      * Causes the Runnable r to executed on the next iteration through the 
  92.      * message queue. The runnable will be run on the thread to which this 
  93.      * handler is attached. 
  94.      * <b>This method is only for use in very special circumstances -- it 
  95.      * can easily starve the message queue, cause ordering problems, or have 
  96.      * other unexpected side-effects.</b> 
  97.      *   
  98.      * @param r The Runnable that will be executed. 
  99.      *  
  100.      * @return Returns true if the message was successfully placed in to the  
  101.      *         message queue.  Returns false on failure, usually because the 
  102.      *         looper processing the message queue is exiting. 
  103.      */  
  104.     public final boolean postAtFrontOfQueue(Runnable r)  
  105.     {  
  106.         return sendMessageAtFrontOfQueue(getPostMessage(r));  
  107.     }  

这里放一块儿说,可以明显看到,post系列的所有方法,立即post,定时post,延时post方法里面都是调用的sedMessage系列的对应的方法。而一个明显的标志就是Message参数都是把Runnable对象传给getPostMessage(r)返回了一个Message对象,如果没猜错,这货又是把Runnable赋给Message里面的一个Runnable属性。来看这个方法:

[java]  view plain  copy
  1. private static Message getPostMessage(Runnable r, Object token) {  
  2.     Message m = Message.obtain();  
  3.     m.obj = token;  
  4.     m.callback = r;  
  5.     return m;  
  6. }  

就知道,果然不出所料,Message里面有一个叫callback的Runnable属性。这样是不是很完美呢,无论你send一个Message,还是post一个Runnnable,最终都是send一个Message。然后我把Runnable放到Message的Runnnable属性里面,接到Message再拿出来,就这么简单。


Handler发送消息的过程是向消息队列中插入一条消息,MessageQueue的next方法就会返回这条消息给Looper,Looper收到这条消息之后就开始处理了,最终消息由looper交由Handler处理,即Handler的dispatchmessage方法会被调用,这是Handler就进入处理消息的阶段。

1.一个Handler只有一个队列;

2.在调用Handler.post(Runnable runnable)方法时,会将runnable封装成一个Message;

3.在队列执行时,会判断当前是否封装了Runnable,如果封装了,就直接执行Runnable,如果没有,将当前的Message传递给handlerMessage(Message msg)处理;

4.Handler在实例化的时候可以设置一个callback<Handler.Callback>,callback也有一个HandlerMessage(Message msg)方法,如果步骤3中的Handler有callback,那么调用的是callback的HandlerMessage(message msg),否则调用自身的handlerMessage(Message msg)方法。

[java]  view plain  copy
  1. private static dispatchMessage(Message msg){
  2.     // 检查message的callback是否为null
  3.     if(msg.callback!=null){
  4.         handlerCallback(msg);
  5.     }
  6.     else{
  7. if(mCallback!=null){
  8. if(mCallback.handlerMessage(msg)){
  9. return;
  10. }
  11. handlerMessage(msg);
  12.      }
  13. }

首先,检查Message的callback是否为null,不为空就通过handleCallback来处理消息。message的callback是一个Runnbale对象,实际上就是Handler的post方法所传递的Runnable参数。

[java]  view plain  copy
  1. private static void handlerCallback(Message msg){
  2.     message.callback.run();
  3. }

其次,检查mCallback是否为空,不为null即调用mCallback的handlerMessage方法来处理消息

[java]  view plain  copy
  1. public interface Callback{
  2.     public boolean handlerMessage(Message msg);
  3. }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值