Android 异步消息处理机制(Handler 、 Looper 、MessageQueue)源码解析

来源:互联网 发布:外汇k线图软件 编辑:程序博客网 时间:2024/04/27 18:25
1、Handler的由来

  当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程。

  Android的UI操作并不是线程安全的(出于性能优化考虑),意味着如果多个线程并发操作UI线程,可能导致线程安全问题。

  为了解决Android应用多线程问题—Android平台只允许UI线程修改Activity里的UI组建,就会导致新启动的线程无法改变界面组建的属性值。

  简单的说:当主线程队列处理一个消息超过5秒,android 就会抛出一个 ANR(无响应)的异常,所以,我们需要把一些要处理比较长的消息,放在一个单独线程里面处理,把处理以后的结果,返回给主线程运行,就需要用的Handler来进行线程建的通信。

2、Handler的作用

2.1 让线程延时执行

主要用到的两个方法:

  • final boolean postAtTime(Runnable r, long uptimeMillis)

  • final boolean postDelayed(Runnable r, long delayMillis)

2.2 让任务在其他线程中执行并返回结果

分为两个步骤:

  • 在新启动的线程中发送消息

      使用Handler对象的sendMessage()方法或者SendEmptyMessage()方法发送消息。

  • 在主线程中获取处理消息

      重写Handler类中处理消息的方法(void handleMessage(Message msg)),当新启动的线程发送消息时,消息发送到与之关联的MessageQueue。而Hanlder不断地从MessageQueue中获取并处理消息。

3、Handler更新UI线程一般使用

  • 首先要进行Handler 申明,复写handleMessage方法( 放在主线程中)
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> Handler handler = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> Handler() {        <span class="hljs-annotation" style="color:#9b859d;box-sizing: border-box;">@Override</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">handleMessage</span>(Message msg) {            <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// TODO 接收消息并且去更新UI线程上的控件内容</span>            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (msg.what == UPDATE) {                <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 更新界面上的textview</span>                tv.setText(String.valueOf(msg.obj));            }            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">super</span>.handleMessage(msg);        }    };</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>
  • 子线程发送Message给ui线程表示自己任务已经执行完成,主线程可以做相应的操作了。
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> Thread() {            <span class="hljs-annotation" style="color:#9b859d;box-sizing: border-box;">@Override</span>            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">run</span>() {                <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// TODO 子线程中通过handler发送消息给handler接收,由handler去更新TextView的值</span>                <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">try</span> {                       <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//do something</span>                        Message msg = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> Message();                        msg.what = UPDATE;                                          msg.obj = <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"更新后的值"</span> ;                        handler.sendMessage(msg);                    }                } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">catch</span> (InterruptedException e) {                    e.printStackTrace();                }            }        }.start();</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li></ul>
4、Handler原理分析

4.1  Handler的构造函数

① public Handler() 
② public Handler(Callbackcallback) 
③ public Handler(Looperlooper) 
④ public Handler(Looperlooper, Callbackcallback)  

  • 第①个和第②个构造函数都没有传递Looper,这两个构造函数都将通过调用Looper.myLooper()获取当前线程绑定的Looper对象,然后将该Looper对象保存到名为mLooper的成员字段中。   
      下面来看①②个函数源码: 
      
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">113</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Handler</span>() {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">114</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">115</span>    }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">127</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Handler</span>(Callback callback) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">128</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>(callback, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">129</span>    }<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//他们会调用Handler的内部构造方法</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">188</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Handler</span>(Callback callback, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> async) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">189</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (FIND_POTENTIAL_LEAKS) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">190</span>      <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> Class<? extends Handler> klass = getClass();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">191</span>      <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> ((klass.isAnonymousClass() ||klass.isMemberClass()         || klass.isLocalClass()) &&<span class="hljs-number" style="color:#06666;box-sizing: border-box;">192</span>                    (klass.getModifiers() & Modifier.STATIC) == <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">193</span>                Log.w(TAG, <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"The following Handler class should be static or leaks might occur: "</span> +<span class="hljs-number" style="color:#06666;box-sizing: border-box;">194</span>                    klass.getCanonicalName());<span class="hljs-number" style="color:#06666;box-sizing: border-box;">195</span>            }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">196</span>        }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">197</span><span class="hljs-javadoc" style="color:#8800;box-sizing: border-box;">/************************************198        mLooper = Looper.myLooper();199        if (mLooper == null) {200            throw new RuntimeException(201                "Can't create handler inside thread that has not called Looper.prepare()");202        }203        mQueue = mLooper.mQueue;204        mCallback = callback;205        mAsynchronous = async;206    }</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li></ul>

  我们看到暗红色的重点部分:

  通过Looper.myLooper()获取了当前线程保存的Looper实例,又通过这个Looper实例获取了其中保存的MessageQueue(消息队列)。每个Handler 对应一个Looper对象,产生一个MessageQueue 
  

  • 第③个和第④个构造函数传递了Looper对象,这两个构造函数会将该Looper保存到名为mLooper的成员字段中。 
      下面来看③④个函数源码:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">136</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Handler</span>(Looper looper) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">137</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>(looper, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">138</span>    } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">147</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Handler</span>(Looper looper, Callback callback) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">148</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>(looper, callback, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">149</span>    }<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//他们会调用Handler的内部构造方法</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">227</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">Handler</span>(Looper looper, Callback callback, boolean <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">async</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">228</span>        mLooper = looper;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">229</span>        mQueue = looper.mQueue;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">230</span>        mCallback = callback;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">231</span>        mAsynchronous = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">async</span>;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">232</span>    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
  • 第②个和第④个构造函数还传递了Callback对象,Callback是Handler中的内部接口,需要实现其内部的handleMessage方法,Callback代码如下:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">80</span>     <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">interface</span> Callback {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">81</span>         <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> boolean More ...<span class="hljs-title" style="box-sizing: border-box;">handleMessage</span>(Message msg);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">82</span>     }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

  Handler.Callback是用来处理Message的一种手段,如果没有传递该参数,那么就应该重写Handler的handleMessage方法,也就是说为了使得Handler能够处理Message,我们有两种办法: 
   
 1. 向Hanlder的构造函数传入一个Handler.Callback对象,并实现Handler.Callback的handleMessage方法   
   
 2. 无需向Hanlder的构造函数传入Handler.Callback对象,但是需要重写Handler本身的handleMessage方法   
    
   也就是说无论哪种方式,我们都得通过某种方式实现handleMessage方法,这点与Java中对Thread的设计有异曲同工之处。

4.2 Handle发送消息的几个方法源码

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">   <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">sendMessage</span>(Message msg)    {        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> sendMessageDelayed(msg, <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">   <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">sendEmptyMessageDelayed</span>(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">int</span> what, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> delayMillis) {        Message msg = Message.obtain();        msg.what = what;        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> sendMessageDelayed(msg, delayMillis);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li></ul>
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">sendMessageDelayed</span>(Message msg, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> delayMillis)    {        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (delayMillis < <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>) {            delayMillis = <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0</span>;        }        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">sendMessageAtTime</span>(Message msg, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> uptimeMillis) {        MessageQueue queue = mQueue;        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (queue == <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {            RuntimeException e = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> RuntimeException(                    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span> + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" sendMessageAtTime() called with no mQueue"</span>);            Log.w(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Looper"</span>, e.getMessage(), e);            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>;        }        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> enqueueMessage(queue, msg, uptimeMillis);    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>

我们可以看出他们最后都调用了sendMessageAtTime(),然后返回了enqueueMessage方法,下面看一下此方法源码:

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">626</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> <span class="hljs-title" style="box-sizing: border-box;">enqueueMessage</span>(MessageQueue queue, Message msg, <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> uptimeMillis) {      <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//把当前的handler作为msg的target属性</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">627</span>        msg.target = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">this</span>;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">628</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (mAsynchronous) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">629</span>            msg.setAsynchronous(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">630</span>        }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">631</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> queue.enqueueMessage(msg, uptimeMillis);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">632</span>    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li></ul>

在该方法中有两件事需要注意:

  1. msg.target = this

      该代码将Message的target绑定为当前的Handler

  2. queue.enqueueMessage 
       
      变量queue表示的是Handler所绑定的消息队列MessageQueue,通过调用queue.enqueueMessage(msg, uptimeMillis)我们将Message放入到消息队列中。

过下图可以看到完整的方法调用顺序:

这里写图片描述 

5、Looper原理分析

  我们一般在主线程申明Handler,有时我们需要继承Thread类实现自己的线程功能,当我们在里面申明Handler的时候会报错。其原因是主线程中已经实现了两个重要的Looper方法,下面看一看ActivityThread.java中main方法的源码:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">main</span>(String[] args) {            <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//......省略</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5205</span>        Looper.prepareMainLooper();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//></span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5206</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5207</span>        ActivityThread thread = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> ActivityThread();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5208</span>        thread.attach(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5209</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5210</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (sMainThreadHandler == <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5211</span>            sMainThreadHandler = thread.getHandler();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5212</span>        }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5213</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5214</span>        AsyncTask.init();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5215</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5216</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">false</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5217</span>            Looper.myLooper().setMessageLogging(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5218</span>   LogPrinter(Log.DEBUG, <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"ActivityThread"</span>));<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5219</span>        }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5220</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5221</span>        Looper.loop();<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//></span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5222</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">5223</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> RuntimeException(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Main thread loop unexpectedly exited"</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5224</span>    }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">5225</span>}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>

5.1 首先看prepare()方法

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">70</span>     <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">prepare</span>() {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">71</span>         prepare(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">true</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">72</span>     }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">73</span> <span class="hljs-number" style="color:#06666;box-sizing: border-box;">74</span>     <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">prepare</span>(boolean quitAllowed) {     <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//证了一个线程中只有一个Looper实例</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">75</span>         <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (sThreadLocal.<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">get</span>() != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">76</span>             <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> RuntimeException(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Only one Looper may be created per thread"</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">77</span>         }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">78</span>         sThreadLocal.<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">set</span>(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> Looper(quitAllowed));<span class="hljs-number" style="color:#06666;box-sizing: border-box;">79</span>     }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

该方法会调用Looper构造函数同时实例化出MessageQueue和当前thread.

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">186</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">private</span> <span class="hljs-title" style="box-sizing: border-box;">Looper</span>(<span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">boolean</span> quitAllowed) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">187</span>        mQueue = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> MessageQueue(quitAllowed);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">188</span>        mThread = Thread.currentThread();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">189</span>    } <span class="hljs-number" style="color:#06666;box-sizing: border-box;">182</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> MessageQueue <span class="hljs-title" style="box-sizing: border-box;">myQueue</span>() {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">183</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span> myLooper().mQueue;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">184</span>    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li></ul>

  prepare()方法中通过ThreadLocal对象实现Looper实例与线程的绑定。 

5.2  loop()方法

<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">109</span>    <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">static</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loop</span>() {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">110</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> Looper me = myLooper();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">111</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (me == <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">112</span>            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">throw</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> RuntimeException(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"No Looper; Looper.prepare() wasn't called on this thread."</span>);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">113</span>        }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">114</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> MessageQueue queue = me.mQueue;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">115</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">118</span>        Binder.clearCallingIdentity();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">119</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> ident = Binder.clearCallingIdentity();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">120</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">121</span>        <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">for</span> (;;) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">122</span>            Message msg = queue.next(); <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// might block</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">123</span>            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (msg == <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">124</span>               <span class="hljs-number" style="color:#06666;box-sizing: border-box;">125</span>                <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span>;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">126</span>            }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">127</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">129</span>            Printer logging = me.mLogging;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">130</span>            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (logging != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">131</span>                logging.println(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">">>>>> Dispatching to "</span> + msg.target + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" "</span> +<span class="hljs-number" style="color:#06666;box-sizing: border-box;">132</span>                        msg.callback + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">": "</span> + msg.what);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">133</span>            }<span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//重点****</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">135</span>            msg.target.dispatchMessage(msg);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">136</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">137</span>            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (logging != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">138</span>                logging.println(<span class="hljs-string" style="color:#0880;box-sizing: border-box;">"<<<<< Finished to "</span> + msg.target + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" "</span> + msg.callback);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">139</span>            }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">140</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">142</span>            <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// identity of the thread wasn't corrupted.</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">143</span>            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">final</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">long</span> newIdent = Binder.clearCallingIdentity();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">144</span>            <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (ident != newIdent) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">145</span>                Log.wtf(TAG, <span class="hljs-string" style="color:#0880;box-sizing: border-box;">"Thread identity changed from 0x"</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">146</span>                        + Long.toHexString(ident) + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" to 0x"</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">147</span>                        + Long.toHexString(newIdent) + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" while dispatching to "</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">148</span>                        + msg.target.getClass().getName() + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" "</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">149</span>                        + msg.callback + <span class="hljs-string" style="color:#0880;box-sizing: border-box;">" what="</span> + msg.what);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">150</span>            }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">151</span><span class="hljs-number" style="color:#06666;box-sizing: border-box;">152</span>            msg.recycleUnchecked();<span class="hljs-number" style="color:#06666;box-sizing: border-box;">153</span>        }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">154</span>    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li><li style="box-sizing: border-box; padding: 0px 5px;">28</li><li style="box-sizing: border-box; padding: 0px 5px;">29</li><li style="box-sizing: border-box; padding: 0px 5px;">30</li><li style="box-sizing: border-box; padding: 0px 5px;">31</li><li style="box-sizing: border-box; padding: 0px 5px;">32</li><li style="box-sizing: border-box; padding: 0px 5px;">33</li><li style="box-sizing: border-box; padding: 0px 5px;">34</li><li style="box-sizing: border-box; padding: 0px 5px;">35</li><li style="box-sizing: border-box; padding: 0px 5px;">36</li><li style="box-sizing: border-box; padding: 0px 5px;">37</li><li style="box-sizing: border-box; padding: 0px 5px;">38</li><li style="box-sizing: border-box; padding: 0px 5px;">39</li><li style="box-sizing: border-box; padding: 0px 5px;">40</li><li style="box-sizing: border-box; padding: 0px 5px;">41</li><li style="box-sizing: border-box; padding: 0px 5px;">42</li></ul>

  首先looper对象不能为空,就是说loop()方法调用必须在prepare()方法的后面。

 Looper一直在不断的从消息队列中通过MessageQueue的next方法获取Message,然后通过代码msg.target.dispatchMessage(msg)让该msg所绑定的Handler(Message.target)执行dispatchMessage方法以实现对Message的处理。

Handler的dispatchMessage的源码如下:

<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-number" style="color:#06666;box-sizing: border-box;">93</span>     <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">dispatchMessage</span>(Message msg) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">94</span>         <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (msg.callback != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">95</span>             handleCallback(msg);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">96</span>         } <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">else</span> {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">97</span>             <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (mCallback != <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">null</span>) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">98</span>                 <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (mCallback.handleMessage(msg)) {<span class="hljs-number" style="color:#06666;box-sizing: border-box;">99</span>                     <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">return</span>;<span class="hljs-number" style="color:#06666;box-sizing: border-box;">100</span>                }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">101</span>            }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">102</span>            handleMessage(msg);<span class="hljs-number" style="color:#06666;box-sizing: border-box;">103</span>        }<span class="hljs-number" style="color:#06666;box-sizing: border-box;">104</span>    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li></ul>

  我们可以看到Handler提供了三种途径处理Message,而且处理有前后优先级之分:首先尝试让postXXX中传递的Runnable执行,其次尝试让Handler构造函数中传入的Callback的handleMessage方法处理,最后才是让Handler自身的handleMessage方法处理Message。

6、如何在子线程中使用Handler

  Handler本质是从当前的线程中获取到Looper来监听和操作MessageQueue,当其他线程执行完成后回调当前线程。

  子线程需要先prepare()才能获取到Looper的,是因为在子线程只是一个普通的线程,其ThreadLoacl中没有设置过Looper,所以会抛出异常,而在Looper的prepare()方法中sThreadLocal.set(new Looper())是设置了Looper的。

6.1 实例代码

 定义一个类实现Runnable接口或继承Thread类(一般不继承)。

<code class="hljs axapta has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">    <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">class</span> <span class="hljs-title" style="color:#66066;box-sizing: border-box;">Rub</span> <span class="hljs-inheritance" style="box-sizing: border-box;"><span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">implements</span></span> <span class="hljs-title" style="color:#66066;box-sizing: border-box;">Runnable</span> {</span>          <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> Handler myHandler;          <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">// 实现Runnable接口的线程体 </span>        @Override          <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> run() {           <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">/*①、调用Looper的prepare()方法为当前线程创建Looper对象并,          创建Looper对象时,它的构造器会自动的创建相对应的MessageQueue*/</span>            Looper.prepare();              <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">/*.②、创建Handler子类的实例,重写HandleMessage()方法,该方法处理除当前线程以外线程的消息*/</span>             myHandler = <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">new</span> Handler() {                  @Override                  <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">void</span> handleMessage(Message msg) {                      String ms = <span class="hljs-string" style="color:#0880;box-sizing: border-box;">""</span>;                      <span class="hljs-keyword" style="color:#0088;box-sizing: border-box;">if</span> (msg.what == <span class="hljs-number" style="color:#06666;box-sizing: border-box;">0x777</span>) {                      }                  }              };              <span class="hljs-comment" style="color:#8800;box-sizing: border-box;">//③、调用Looper的loop()方法来启动Looper让消息队列转动起来</span>            Looper.loop();          }    }</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li></ul>

注意分成三步: 

1.调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue。  

2.有了Looper之后,创建Handler子类实例,重写HanderMessage()方法,该方法负责处理来自于其他线程的消息。  

3.调用Looper的looper()方法启动Looper。

  然后使用这个handler实例在任何其他线程中发送消息,最终处理消息的代码都会在你创建Handler实例的线程中运行。

7、总结

Handler 
      发送消息,它能把消息发送给Looper管理的MessageQueue。 
      处理消息,并负责处理Looper分给它的消息。 
Message 
      Handler接收和处理的消息对象。 
Looper 
      每个线程只有一个Looper,它负责管理对应的MessageQueue,会不断地从MessageQueue取出消息,并将消息分给对应的Hanlder处理。   
       
      主线程中,系统已经初始化了一个Looper对象,因此可以直接创建Handler即可,就可以通过Handler来发送消息、处理消息。 程序自己启动的子线程,程序必须自己创建一个Looper对象,并启动它,调用Looper.prepare()方法。

prapare()方法:保证每个线程最多只有一个Looper对象。  

looper()方法:启动Looper,使用一个死循环不断取出MessageQueue中的消息,并将取出的消息分给对应的Handler进行处理。  

MessageQueue:由Looper负责管理,它采用先进先出的方式来管理Message。 

  Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。  
   
  Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。



原文地址: http://blog.csdn.net/amazing7/article/details/51424038

0 0
原创粉丝点击