| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
weibinbin
5年前发布

两张图看透Android Handler使用与机制

   <h2><strong>1.Handler的使用</strong></h2>    <p style="text-align:center"><img src="https://simg.open-open.com/show/0bd2151c1f869cb2248df4ea4aeee26a.png"></p>    <ul>     <li> <p>如图所示,需要做的操作有两步:</p>      <ol>       <li> <p>在主线程中实例化一个Handler,并且重写HandleMessage方法用来处理子线程发送来的消息。</p> </li>       <li> <p>在子线程中,首先声明Message对象,并将Message使用主线程中实例化的Handler的sendMessage(Message)方法发送给主线程。</p> </li>      </ol> <pre>  <code class="language-java">public class MainActivity extends AppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        final Handler handler=new Handler(){            @Override            public void handleMessage(Message m){                //更新ui操作            }        };        new Thread(){//子线程开启            @Override            public void run(){                Message m=new Message();                handler.sendMessage(m);            }        };    }  }</code></pre> </li>    </ul>    <h2><strong>2.Handler的机制</strong></h2>    <p><img src="https://simg.open-open.com/show/38642d72d7f20b4fc9b3b2d4873321c7.png"></p>    <ul>     <li> <p>在使用sendMessage和handleMessage之前是有很多已经隐藏的封装好的过程的,现在一一讲解。</p> </li>    </ul>    <h2><strong>2.1 被消息传递的线程A准备</strong></h2>    <ul>     <li> <p>首先要在被消息传递的线程中创建Looper,因为Handler创建的时候要绑定当前线程的Looper,使用Looper.prepare()建立。</p>      <ul>       <li>Looper.prepare() <pre>  <code class="language-java">public static void prepare() {  prepare(true);  }  private static void prepare(boolean quitAllowed) {  if (sThreadLocal.get() != null) {      throw new RuntimeException("Only one Looper may be created per thread");  }  sThreadLocal.set(new Looper(quitAllowed));  }  private Looper(boolean quitAllowed) {      mQueue = new MessageQueue(quitAllowed);      mThread = Thread.currentThread();  }</code></pre> <p>总的来说,prepare干了两件事: <strong>创建MessageQueue和绑定当前线程。</strong></p> </li>      </ul> </li>     <li> <p>然后使用Looper.loop()让Looper开始循环访问MessageQueue。</p>      <ul>       <li> <p>Looper.loop();</p> <pre>  <code class="language-java">public static void loop() {    // 拿到与当前线程关联的looper对象      final Looper me = myLooper();      if (me == null) {          throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");      }      final MessageQueue queue = me.mQueue;      .......................................        for (;;) {          Message msg = queue.next(); // might block          ...................................          msg.target.dispatchMessage(msg);          ..........................................          msg.recycleUnchecked();// 回收Message对象      }  }</code></pre> <p>总的来说,loop干了三件事:</p> <p>1.拿到当前线程的looper。</p> <p>2.根据looper拿到MessageQueue。</p> <p>3.使用for循环对MessageQueu进行无限循环询问。</p> <p>在for循环中也主要干了三件事:</p> <p>1.从消息队列中取消息,如果没有就阻塞。</p> <p>2.调用msg.target.dispatchMessage(msg)方法对Message进行处理。</p> <p>3.处理完成后调用msg.recycleUnchecked()回收资源。</p> </li>      </ul> </li>     <li> <p>创建Handler,作为线程间通信的工具。</p> <pre>  <code class="language-java">public Handler(Looper looper, Callback callback, boolean async){        mLooper = looper;        // 与这个Handler关联的Looper中的消息队列        mQueue = looper.mQueue;        ...............  }</code></pre> <p>创建Handler时将当前线程的Looper和Looper中的MessageQueue取到。</p> </li>    </ul>    <h2><strong>2.2 传递消息的线程B准备</strong></h2>    <ul>     <li> <p>创建Message时,使用Message.obtain()的效果大于New Message(),因为享元模式,维护了一个大小为50的Message对象池,比重复去创建Message更加高效。</p> </li>     <li> <p>Handler.sendMessage(Message)方法最终会调用sendMessageAtTime方法。</p> <pre>  <code class="language-java">public boolean sendMessageAtTime(Message Message, long uptimeMillis) {        // 1. 获取Hndler中的消息队列        MessageQueue queue = mQueue;        if (queue == null) {            RuntimeException e = new RuntimeException(                    this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);            return false;        }        // 2. 将要发送消息和时间入队        return enqueueMessage(queue, Message, uptimeMillis);    }</code></pre> <p>总的来说,做了两件事:</p> <p>1.获取handler中的MessageQueue。</p> <p>2.调用enqueueMessage方法。</p> <p>enqueueMessage()方法代码如下:</p> <pre>  <code class="language-java">private boolean enqueueMessage(MessageQueue queue, Message Message, long uptimeMillis) {        // 1. 将Handler赋值给Message的target         Message.target = this;        if (mAsynchronous) {            Message.setAsynchronous(true);        }        // 2. 将Message加入到消息队列中(还有Handler)        return queue.enqueueMessage(Message, uptimeMillis);    }</code></pre> <p>总的来说,做了两件事:</p> <p>1.将handler赋值给Message.target。</p> <p>2.并且将Message放入MessageQueue中。</p> </li>    </ul>    <h2><strong>2.3 线程间通信</strong></h2>    <ul>     <li> <p>线程B的sendMessage流程执行完毕,至于线程A的Looper和Handler都已经创建好了,并且开始处理MessageQueue中的Message,还记得之前for循环中Message.target.dispatchMessage()方法吗,其实这里的Message.target就是handler,而且dispatchMessage()方法的源码如下:</p> <pre>  <code class="language-java">public void dispatchMessage(Message msg) {     ..........     handleMessage(msg);  }</code></pre> 在其中调用了handleMessage()方法,并且handleMessage()方法是个空方法,没有内容。所以我们只用重写这个方法就可以对线程B返回的消息进行处理了。</li>    </ul>    <h2><strong>3.一些问题</strong></h2>    <ul>     <li> <p>为什么Activity主线程没有执行Looper.prepare()和Looper.loop()?</p> <p>因为在ActivityThread的main方法中已经执行了这两个方法。</p> </li>     <li> <p>一个线程可以拥有几个Looper?几个Handler?</p> <p>一个线程只能拥有一个Looper,无数个Handler。</p> </li>     <li> <p>如何从主线程发送消息给子线程?</p> <p>在子线程中先建立Looper,然后再建立Handler,依靠sendMessage和handleMessage即可。</p> </li>    </ul>    <p> </p>    <p>来自:http://www.jianshu.com/p/8862ab82d0f4</p>    <p> </p>    
 本文由用户 weibinbin 自行上传分享,仅供网友学习交流。所有权归原作者,若您的权利被侵害,请联系管理员。
 转载本站原创文章,请注明出处,并保留原始链接、图片水印。
 本站是一个以用户分享为主的开源技术平台,欢迎各类分享!
 本文地址:https://www.open-open.com/lib/view/open1473834554158.html
消息系统 安卓开发 Android开发 移动开发