Handler发送sendMessage和postRunnable的区别

https://blog.csdn.net/lishuangling21/article/details/50848588

都是发送消息。sendMessage使用统一消息处理回调函数,postRunnable的消息自备消息处理回调函数

Handler发送sendMessage和postRunnable的区别

原创 2016年03月10日 17:31:20
[java] view plain copy
 
  1. </pre><p class="p1"><span class="s1">先从平时的应用入手吧。试想这样一个场景,我们有一个下载文件的需求,而且我们在界面上要显示下载的状态:未下载,下载中,已下载。这个时候我们该怎么办?首先可以在界面上放一个Button,显示未下载,然后设置点击事件,点击后显示下载中,并开启一个线程去下载(这里用线程sleep代替,实际未下载)。等下载完成后,再把Button上的文字改为已下载。我们来试一下:</span></p><pre name="code" class="java">public class MainActivity extends AppCompatActivity {  
  2.     private Button mButton;  
  3.     private Thread mThread;  
  4.   
  5.     @Override  
  6.     protected void onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         setContentView(R.layout.activity_main);  
  9.         mButton = (Button) findViewById(R.id.bt_1);  
  10.         initThread();  
  11.         mButton.setOnClickListener(new View.OnClickListener() {  
  12.             @Override  
  13.             public void onClick(View v) {  
  14.                 mButton.setText("开启下载线程下载中");  
  15.                 mThread.start();      
  16.         mButton.setClickable(false);  
  17.             }  
  18.         });  
  19.     }  
  20.   
  21.     private void initThread() {  
  22.         mThread = new Thread(new Runnable() {  
  23.             @Override  
  24.             public void run() {  
  25.                 try {  
  26.                     Thread.sleep(2000);  
  27.                 } catch (InterruptedException e) {  
  28.                     e.printStackTrace();  
  29.                 }  
  30.                 mButton.setText("已下载完成");  
  31.             }  
  32.         });  
  33.     }  
  34. }  

编译运行,一切正常,然后我们点击一下按钮:肏,crash掉了。好吧,淡定,淡定,我们看一下log:

03-10 16:15:22.707 10592-11189/com.example.gray_dog3.handlertest E/AndroidRuntime: FATAL EXCEPTION: Thread-302

                                                                                   Process: com.example.gray_dog3.handlertest, PID: 10592

                                                                                   android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread    that created a view hierarchy can touch its views.

                                                                                   at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:7177)

                                                                                   at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:1065)

 好吧,用我过了四级的英语水平给翻译下吧,错误的线程调用异常,发生Crash的地点是ViewRootImpl中调用checkThread方法中。温馨提示是:只有创建View的线程才能对摸摸它创建的View。。。好吧,顺着代码一瞅,果然,我再mThread中摸了一把在UI线程中创建的mButton。所以报了这个错。为了更直观的看到报错原因,我们直接跳到源码ViewRootImpl的checkThread方法,看它做了什么。

[java] view plain copy
 
  1. void checkThread() {  
  2.         if (mThread != Thread.currentThread()) {  
  3.             throw new CalledFromWrongThreadException(  
  4.                     "Only the original thread that created a view hierarchy can touch its views.");  
  5.         }  
  6.     }  

就是这货了,但是Android为什么要这样搞呢?我们仔细看这句话,只有创建了View的线程才能对这个View进行操作。而我们一般View都是为了显式在UI上的。Android正是为了防止我们在非UI线程去操作这些UI上的控件,才加了限制的。因为UI体验对用户来说是最直观的,如果谁都有权限去搞一发,那UI要么很乱,要么控制很复杂。但是总不能难搞就不让搞把?实际上是可以的,Android为我们提供一个工具,来让我们进行线程间的消息传递,就是我们接下来要讲的主角:Handler。

对于Handler来说上面的问题可以轻易解决,看代码:

 

[java] view plain copy
 
  1. <pre name="code" class="java">public class MainActivity extends AppCompatActivity {  
  2.     private Button mButton;  
  3.     private Thread mThread;  
  4.     private Handler mHandler;  
  5.     private int a=3,b=5;  
  6.     @Override  
  7.     protected void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_main);  
  10.         mHandler=new Handler(){  
  11.             @Override  
  12.             public void handleMessage(Message msg) {  
  13.                  mButton.setText("已下载完成");  
  14.             }  
  15.         };  
  16.         initThread();  
  17.         mButton = (Button) findViewById(R.id.bt_1);  
  18.         mButton.setOnClickListener(new View.OnClickListener() {  
  19.             @Override  
  20.             public void onClick(View v) {  
  21.                 mButton.setText("开启下载线程下载中");  
  22.                 mThread.start();  
  23.                 mButton.setClickable(false);  
  24.             }  
  25.         });  
  26.   
  27.     }  
  28.   
  29.     private void initThread() {  
  30.         mThread = new Thread(new Runnable() {  
  31.             @Override  
  32.             public void run() {  
  33.                 try {  
  34.                     Thread.sleep(2000);  
  35.                 } catch (InterruptedException e) {  
  36.                     e.printStackTrace();  
  37.                 }  
  38.                 mHandler.sendMessage(Message.obtain());  
  39.             }  
  40.         });  
  41.     }  
  42. }  

在上面的代码中,我们只是在主线程里创建一个Handler,重写它的handleMessage方法,然后子线程里拿到这个Handler,下载结束后用Handler给主线程发一个消息。然后主线程收到消息后,再去改变Button上显示的文字。

上面只是Handler最普通的一个应用场景,发送消息,接收消息。实际上这也是它所有的能做的事。有人说还有postRunnable的吗?怎么能说是只有发送和就收消息呢?好,我们带着这个疑问来看下Handler究竟是什么:

 

首先看Android源码注释,

 A Handler allows you to send and process {@link Message} and Runnable

 * objects associated with a thread's {@link MessageQueue}.  Each Handler

 * instance is associated with a single thread and that thread's message

 * queue.  When you create a new Handler, it is bound to the thread /

 * message queue of the thread that is creating it -- from that point on,

 * it will deliver messages and runnables to that message queue and execute

 * them as they come out of the message queue.

翻译:handler使你能够给绑定的线程发送一个消息或者一个Runnable对象。每一个Handler的实例都与一个线程和该线程的消息队列进行绑定。

从创建出一个Handler的时候,Handler就与创建出它的那个线程绑定了,它将发送消息或者Runnable对象到该线程的消息队列里面。

There are two main uses for a Handler: 

(1) to schedule messages and runnables to be executed as some point in the future; 

 

 (2) to enqueue an action to be performed on a different thread than your own.

Handler两种主要用途:

一、在将来某个时刻或者某个逻辑节点调度一个message,或者Runnable执行。说人话就是将来某个时间节点或者逻辑节点,想要做什么事可以通过Handler来做。

二、给别的线程插入一个操作。就是你想在别的线程中执行一些代码,可以拿到它的Handler给他发消息或postRunnnable。

更直观的描述:

由图中可以看出,Hanler是用来发送消息,和接收消息的,所有发送的消息都是一个Message的实例,放在MessageQueue中。Looper则负责从MessageQueue中取出消息,发送给Handler,交由Handler去处理。

上面是对Handler一些概念性的描述和结构图,让我们对Handler有了一些感性认知。要用Handler就要new一个Handler出来,接下来看看Handler都有哪些构造方法(一个无聊的过程,构造方法不就是new出一个实例么,带参数就是给响应的属性赋初始值,其实我们在看构造方法时最终要的还是要看它给哪些属性赋初始值,因为既然提出一个构造方法给一个属性赋值,说明这个属性相对来说用的比较多。一般也是研究这个类应该关注的重点):

 

[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(null, false);  
  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, null, false);  
  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再拿出来,就这么简单。

好了,就先讲这么多吧,头疼,等我有空再来整理吧,先留个记号,接下来讲MessageQueue和Looper,主要讲MessageQueue如何插入一条消息,以及如何把定时的消息排队,还有Looper的死循环是运行在哪个线程里,Message里面都有哪些属性,都是干嘛的,用源码说话。好了就先这样。





 

 

 

 



 

 

 



 

 
 
posted @ 2018-03-29 10:58  sky20080101  阅读(624)  评论(0)    收藏  举报