Android 从源码角度理解Handler、Looper、MessageQueue之间关系

为什么?

多问为什么是解决并理解问题的最好的办法,Handler是Android SDK中的类,Android为什么要引入Handler、Looper、MessageQueue呢?

线程间通讯,消息队列处理

经常使用的场景有通过Handler更新UI,貌似我们理解中更新UI只能在主线程
这句话好像是对的,其实更准确的说法是更新UI只能在UI线程,即要更新的UI所在ViewRoot创建时候的线程,如果当前ViewRoot是在子线程创建的,更新ViewRoot里面的UI必须在这个子线程中更新,而我们常见的ViewRoot创建都是在主线程,所以把常见的结果当成标准结果是万万不可的。
为什么采用消息队列的形式呢?消息队列的方式可以解决线程堵塞数据混乱等问题。

言归正传

Handler

Handler是用来发送和处理消息的
Handler对象的创建需要绑定一个指定线程的Looper, 即Handler是和线程相关的,如一个Handler绑定的是一个子线程中的Looper,那么这个Handler就不能用来更新UI线程(主线程)。

Looper

Looper是通过for (;;)循环来不停的把MessageQueue中的消息交给Handler处理

MessageQueue

用来存储Message的消息队列

源码分析(类分析)

Handler的构造函数中只有2个基本构造函数
1.未指定Looper

public Handler(Callback callback, boolean async) {
        //省略部分代码
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

2.指定Looper

 public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

其中未指定Looper通过mLooper = Looper.myLooper(); 来获取当前线程中的Looper
让我们来看看Looper.myLooper();究竟做了哪些操作 ,打开Looper源码

public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }

额。。。sThreadLocal是什么鬼,怎么通过他返回一个Looper 继续查看

static final ThreadLocal sThreadLocal = new ThreadLocal();

原来是一个ThreadLocalThreadLocal用于保存某个线程共享变量,当前即为保存线程中Looper变量,通过sThreadLocal来获取当前线程的Looper,在过sThreadLocal没有进行set()的时候sThreadLocal.get() 为空,为空的时候

 if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }

会提示RuntimeException 提示我们在创建对象之前必须先执行Looper.prepare()
那为什么我们经常在使用Handler更新UI的时候没有执行过呢,其实并不是没有执行,只不过并不需要我们来执行,在ActivityThreadmain方法中已经执行过Looper.prepareMainLooper();所以不需要我们执行,系统已经帮我们执行过了
而在子线程中创建Handler 或指定的子线程中的Looper,必须我们手动执行Looper.prepare()不然就会报RuntimeException异常信息
继续查看Looper.prepare()执行了哪些操作

public static void prepare() {
        prepare(true);
    }

private static void prepare(boolean quitAllowed) {
        //如果已经存在了Looper也会报异常 所以Looper.prepare()只能必须执行1次
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //保存在sThreadLocal中
        sThreadLocal.set(new Looper(quitAllowed));
    }

继续看new Looper(quitAllowed)的处理

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

创建MessageQueue对象 绑定当前线程

小结

自此三者的关系明朗了起来
Handler绑定了Looper,Looper创建了一个MessageQueue对象
Handler拥有Looper、MessageQueue成员变量

源码分析(如何发处理消息)

通过层层跳转,发送消息都会执行到sendMessageAtTime方法中

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);
    }

也就是enqueueMessage(queue, msg, uptimeMillis)方法

 private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //设置msg的target为当前Handler
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

这里主要就是设置msg的target为当前Handler然后调用MessageQueue的enqueueMessage(msg, uptimeMillis)方法把此msg存储到消息队列中
到了这里好像结束了,源码分析完了,等等还没消息处理呢,怎么只有发送,没有接收处理 自此Looper.loop()方法登场了

public static void loop() {
        //省略部分代码
        for (;;) {
        Message msg = queue.next(); // might block
           //省略部分代码
            try {
                //执行msg的target(Handler)的dispatchMessage方法
                msg.target.dispatchMessage(msg);
                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
           //省略部分代码
        }
    }

原来for循环不停的取出msg执行msg对于的Handler中的dispatchMessage(msg)方法

 public void dispatchMessage(Message msg) {
        //如果msg创建的时候设置了callback则会执行callback的run方法
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            //如果在创建Handler的时候设置了callback则会执行callback的handleMessage方法
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            //都没有设置则会执行Handler的handleMessage方法
            handleMessage(msg);
        }
    }

至此 Handler的发送与消息处理整个流程就解析完毕

总结

线程中使用Handler步骤
1.Looper.prepare() 准备Looper(主线程已经在ActivityThread中执行);
2.new Handler() 创建Handler(注意指定的Looper线程或创建对象所在的线程)
3.Looper.loop()启动Looper 循环取出MessageQueue中的消息交给Handler处理(主线程已经在ActivityThread中执行)

发送消息流程
1.Handler.sendMessageAtTime() 定时发送消息
2.MessageQueue.enqueueMessage()存储消息至消息队列
3.Handler.dispatchMessage(msg);消息的分发处理

你可能感兴趣的:(Android 从源码角度理解Handler、Looper、MessageQueue之间关系)