Handler、Looper、MessageQueue解析

1 篇文章 0 订阅
1 篇文章 0 订阅
本篇文章是在已经会使用Handler并对handler有一定了解的情况下,对Handler的原理做探讨。

1. UI线程的Looper
UI线程的Looper的创建是在ActivityThread中创建的;
ActivityThread它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口,AMS为Client、ActivityThread.ApplicationThread为Server)负责调度和执行activities、broadcasts和其它操作。
main函数源码:
这里写图片描述
在main函数里为UI线程创建了Looper,并启动Looper.loop()中的for循环来处理接收到的Message。
来看看Looper的源码;
在Looper中首先创建一个ThreadLocal常量,ThreadLocal在上篇博客中已有介绍;他就好比是一个小区管理员,Thread的实例(new Thread)就是这个小区的各个住户,每户住户房间的设备就是Looper(new Looper)实例;住户可以创建设备,也可以不创建,但每户只能有一套设备(即一个Thread 实例只能绑定一个Looper);小区管理员(ThreadLocal)记录每户住户(Thread实例)的信息,并为其分配钥匙;每个住户只要一把钥匙,只能开对应的房间门并使用该房间的设备。
这里写图片描述

Looper实例创建的主要过程
这里写图片描述

线程每次创建Looper实例之前,都会让小区管理员(ThreadLocal)检查一下该住户(线程实例)是否有设备(Looper实例),如果有就抛出异常,没有就创建,并由小区管理员(ThreadLocal)管理两者之间的关系,以保证每个住户(线程实例)最多只能有一套设备(Looper实例),且每套设备(Looper实例)只能属于一个住户(线程实例)。

MessageQueue创建比较简单,与Looper一同创建;Looper与MessageQueue一一对应;MessageQueue主要是用来存储管理Message。
这里写图片描述
以上就是UI线程的Looper和MessageQueue的创建过程。

2. 普通线程的Looper
普通线程的Looper创建过程和UI线程的创建过程相似,区别主要有三点:
1.UI线程的Looper是由系统创建的,在ActivityThread中创建。
2.普通线程的Looper是手动创建的,调用 Looper.prepare()和 Looper.loop();方法为此线程创建Looper。
3.UI线程的Looper不可以退出,普通线程的Looper可以退出。

3. Handler与Looper、MessageQueue的关系
先来看看Handler的创建:
这里写图片描述
myLooper()源码
这里写图片描述
由上图源码不难分析出,只要在同一线程中创建的Handler实例,其对应的Looper实例和MessageQueue都是一样的。
通过以上分析可以总结出Handler与Looper、MessageQueue、Thread有如下关系:
1.Looper 与 MessageQueue一一对应(即一对一关系)
2.Handler与Looper是多对一关系。
3.Thread与Looper也是一一对应关系(Thread最多只能有一个Looper)。

4. 消息的发送、存储、处理
Handler发送消息的方法有很多种,但最终调用的方法都是调用的都是sendMessageAtTime方法。

/**
     * Enqueue a message into the message queue after all pending messages
     * before the absolute time (in milliseconds) <var>uptimeMillis</var>.
     * <b>The time-base is {@link android.os.SystemClock#uptimeMillis}.</b>
     * Time spent in deep sleep will add an additional delay to execution.
     * You will receive it in {@link #handleMessage}, in the thread attached
     * to this handler.
     * 
     * @param uptimeMillis The absolute time at which the message should be
     *         delivered, using the
     *         {@link android.os.SystemClock#uptimeMillis} time-base.
     *         
     * @return Returns true if the message was successfully placed in to the 
     *         message queue.  Returns false on failure, usually because the
     *         looper processing the message queue is exiting.  Note that a
     *         result of true does not mean the message will be processed -- if
     *         the looper is quit before the delivery time of the message
     *         occurs then the message will be dropped.
     */
    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        MessageQueue queue = mQueue;
        if (queue == null) {
            RuntimeException e = new RuntimeException(
                    this + " sendMessageAtTime() called with no mQueue");
            Log.w("Looper", e.getMessage(), e);
            return false;
        }
        return enqueueMessage(queue, msg, uptimeMillis);
    }

把Message加入到MessageQueue容器;
这里写图片描述
这里如果Handler发送了message就会被存储到对应的MessageQueue中。
再来看看Message的处理:
Message的处理是在Looper.loop()方法,重要的地方尽量做了注释:

  /**
   * Run the message queue in this thread. Be sure to call
   * {@link #quit()} to end the loop.
   */
    public static void loop() {
        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;
        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();
        for (;;) {//for循环,始终遍历MessageQueue,如果有message就处理
            Message msg = queue.next(); // might block
            if (msg == null) {
                return;
            }
           Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }
            msg.target.dispatchMessage(msg);//重点:在保存message时就为此message绑定了Handler,
                                            // 此时调用该Handler的dispatchMessage方法来处理消息
            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }
            msg.recycleUnchecked();//msg处理完后就会被回收
        }
    }

Looper.loop()用一个死循环来遍历对应线程的MessageQueue,有Message就分发给与之绑定的Handler(调用Handler的dispatchMessage方法)处理。message绑定handler是在Handler发送消息时。
Handler的dispatchMessage处理消息的过程:

 /**
  * Handle system messages here.
  */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);//处理post出来的Message。
        } else {//处理send出来的Message
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {//如果实现Callback的handleMessage方法且返回为true则不再调用Handler的handleMessage方法
                    return;
                }
            }
            handleMessage(msg);//如果没有实现Callback,或者实现Callback的handleMessage方法,但返回为false都会调用Handler的handleMessage方法
        }
    }

消息的发送、接收、处理大致如此。

总结:Handler、Looper、MessageQueue可以看成是一个生产者与消费者模式;Handler充当生成者,MessageQueue是一个容器,Looper是消费者;Handler最主要的作用就是 线程间通信

关于Handler的使用,以后再做介绍或参见其他博客。
以上仅为个人见解,如有指导意见请留言;也可加qq:1148392049
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值