美文网首页Android进阶之路Android技术知识Android开发
10分钟掌握Android消息机制(三)Looper的工作原理

10分钟掌握Android消息机制(三)Looper的工作原理

作者: 夏天吃冰棍 | 来源:发表于2019-06-18 00:45 被阅读4次

    本文为个人学习笔记分享,没有任何商业化行为,对其他文章的引用都会标记。如有侵权行为,请及时提醒更正!如需转载请表明出处
    本文主要来源是 任玉刚大神的《Android开发艺术探索》


    Looper在Android的消息机制中扮演者消息循环的角色,具体来说就是它会不停地从MessageQueue中查看是否有新消息,如果有就会立即处理,否则就一直阻塞在那里。首先看一下它地构造方法,在构造方法中它会创建一个MessageQueue即消息队列,然后将当前线程的对象保存起来,如下所示。

      private Looper(boolean quitAllowed){
          mQueue=new MessageQueue(quitAllowed);
          mThread=Thread.currentThread();
      }
    

    我们知道,Handler的工作需要Looper,没有Looper的线程就会报错,那么如何为一个线程创建Looper呢?其实很简单,通过Looper.prepare()即可为当前线程创建一个Looper,接着通过Looper.looper()来开启消息循环,如下所示。

      new Thread("Thread#2"){
        @Override
        public void run(){
            Looper.prepare();
            Handler handler=new Handler();
            Looper.looper();
        }
      }
    

    Looper除了prepare方法外,还提供了prepareMainLooper方法,这个方法主要是给主线程也就是ActivityThread创建Looper使用的,其本质也是通过prepare方法来实现。由于主线程的Looper比较特殊,所以Looper提供了一个getMainLooper的方法,通过它可以在任何地方获取到主线程的Looper。Looper也是可以退出的,Looper提供了quit和quitSafely来退出一个Looper,二者的区别是:quit会直接退出Looper,而quitSafely只是设定一个退出标记,然后把消息队列中的已有消息处理完毕才安全退出。Looper退出后,通过Handler发送的消息会失败,这个时候Handler的send方法返回false。在子线程中,如果手动为其创建了Looper,那么在所有的事情完成以后应该调用quit方法来终止循环消息,否则这个子线程就会一直处于等待的状态,而如果退出Looper以后,这个线程就会立刻终止,因此建议不需要的时候终止Looper。
    总结

    • Handler的工作需要Looper,没有Looper的线程就会报错,通过Looper.prepare()即可为当前线程创建一个Looper,接着通过Looper.looper()来开启消息循环
    • Looper提供了一个getMainLooper的方法,通过它可以在任何地方获取到主线程的Looper。
    • Looper提供了quit和quitSafely来退出一个Looper,二者的区别是:quit会直接退出Looper,而quitSafely只是设定一个退出标记,然后把消息队列中的已有消息处理完毕才安全退出。
    • Looper退出后,通过Handler发送的消息会失败,这个时候Handler的send方法返回false。在子线程中,如果手动为其创建了Looper,那么在所有的事情完成以后应该调用quit方法来终止循环消息,否则这个子线程就会一直处于等待的状态,而如果退出Looper以后,这个线程就会立刻终止,因此建议不需要的时候终止Looper。
    Looper中的loop

    Looper中最重要的方法loop,只有调用loop后,消息循环系统才会真正起作用。

    public static void loop() {
            .......
            for (;;) {
                //开启无线循环 调用MessageQueue,当MessageQueue无数据时,阻塞。
                Message msg = queue.next(); // might block
                if (msg == null) {
                    // Looper退出的唯一情况就是MessageQueue的next方法返回null
                    return;
                }
                final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
                final long dispatchEnd;
                try {
                    //分发事件
                    msg.target.dispatchMessage(msg);
                    dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
                } finally {
                    if (traceTag != 0) {
                        Trace.traceEnd(traceTag);
                    }
                }
               ......
                msg.recycleUnchecked();
            }
        }
    

    Looper的loop方法的工作过程也比较好理解,loop方法是一个死循环,唯一跳出循环的条件就是MessageQueue的next方法返回null。当Looper的quit方法被调用时,Looper就会调用MessageQueue的quit或者quitSafely方法来通知消息队列退出,当消息队列被标记为退出状态时,它的next方法就会返回null。如果MessageQueue的next方法返回了新消息,Looper就会处理这条消息:msg.target.dispatchMessage(msg);这里msg.target就是发送了这个消息的handler对象,这样Handler发送的消息最终又会交给它的dispatchMessage方法。但是这里就不同了,Handler的dispatchMessage方法是在创建Handler时所使用的Looper中执行的,这样就成功的将代码逻辑切换到指定线程中去执行了。
    总结

    • Looper的loop方法的工作过程也比较好理解,loop方法是一个死循环,唯一跳出循环的条件就是MessageQueue的next方法返回null。
    • 当Looper的quit方法被调用时,Looper就会调用MessageQueue的quit或者quitSafely方法来通知消息队列退出,当消息队列被标记为退出状态时,它的next方法就会返回null。
    • MessageQueue的next方法返回了新消息msg.target.dispatchMessage(msg);这里msg.target就是发送了这个消息的handler对象,这样Handler发送的消息最终又会交给它的dispatchMessage方法。
      整理写作不易,请小伙伴多多支持,麻烦请点赞关注支持一下,😘😘😘。

    相关文章

      网友评论

        本文标题:10分钟掌握Android消息机制(三)Looper的工作原理

        本文链接:https://www.haomeiwen.com/subject/wvbtqctx.html