Handler、Looper、Message、MessageQueue

Looper类主要参数有:

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;
    final Thread mThread;

初始化Handler之前,需要调用Looper.prepare(),来new一个Looper实例,该实例存放在ThreadLocal中



Looper初始化好后,需要调用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();

        // Allow overriding a threshold with a system prop. e.g.
        // adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
        final int thresholdOverride =
                SystemProperties.getInt("log.looper."
                        + Process.myUid() + "."
                        + Thread.currentThread().getName()
                        + ".slow", 0);

        boolean slowDeliveryDetected = false;

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            final Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            final long traceTag = me.mTraceTag;
            long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
            long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
            if (thresholdOverride > 0) {
                slowDispatchThresholdMs = thresholdOverride;
                slowDeliveryThresholdMs = thresholdOverride;
            }
            final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
            final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);

            final boolean needStartTime = logSlowDelivery || logSlowDispatch;
            final boolean needEndTime = logSlowDispatch;

            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
            }

            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);
                }
            }
            if (logSlowDelivery) {
                if (slowDeliveryDetected) {
                    if ((dispatchStart - msg.when) <= 10) {
                        Slog.w(TAG, "Drained");
                        slowDeliveryDetected = false;
                    }
                } else {
                    if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
                            msg)) {
                        // Once we write a slow delivery log, suppress until the queue drains.
                        slowDeliveryDetected = true;
                    }
                }
            }
            if (logSlowDispatch) {
                showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
            }

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            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();
        }
    }

代码中主要在 for (;;) ,会无限循环获取MessageQueue的每个Message msg,并且调用msg.target.dispatchMessage(msg),其中msg.target是一个Handler,这句代码其实就是,将msg回调给Handler的dispatchMessage方法,dispatchMessage调用了handleMessage方法,所以,咱们创建的Handler就可以收到消息了。这里大家会有个疑问,msg.target是在什么时候设置的呢?后面讲Handler时会给出答案,大家接着往下看。

Handler类主要参数有:


image.png

new Handler()时,最终会调用如下构造方法:


image.png

构造方法中初始化了:mLooper、mQueue、mCallback。
mLooper、mQueue都是拿的Looper中已初始化好的,looper、mQueue(所以,Handler中对mLooper、mQueue的操作,都会造成Looper中looper、mQueue的同步变化)。

调用hadnler.sendMessage()等方法发送消息时,最终会调用sendMessageAtTime()方法:

image.png

然后调用enqueueMessage()方法,Message加入mQueue中:
image.png

上图中,msg.target = this;就解释了讲Looper时,最后那个疑问。

再补充几个知识点:
Looper类中的ThreadLocal<Looper> sThreadLocal变量,通过set()/get()来存取当前线程的Looper,怎么实现的呢?我们先来看看ThreadLocal源码:

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
 public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

可以看到,get和set都是间接从一个ThreadLocalMap中取值,而这个ThreadLocalMap是通过getMap(t),传入当前线程得到的。我们来看看这个getMap(t):

    ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
    }

这里返回了Thread类中的threadLocals变量,我们看看这个变量的代码:

 ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocalMap的源码太长,我就不贴了。简单介绍一下,它就是一个hash Map,用来维护ThreadLocal变量的。
根据以上代码可以得出:每个Thread有唯一的一个ThreadLocalMap,ThreadLocalMap中唯一存放了一个Looper。因此只要是在一个线程中获取Looper,始终获取到的是同一个。
所以咱们可以得出: 一个Thread只有一个Looper,一个Looper只有一个MessageQueue。而一个Looper可以对应多个Handler(因为new Handler可以传参Looper)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容