从HandlerThread源码理清handler、looper与messageQueue之间的关系

前端时间看到一篇关于HandlerThread 的介绍博文,感觉写的不错;再由于近段时间遇到的一个面试题:looper是如何与线程绑定到一起的?当时回答的很不流畅,因此回去之后又跟着源码分析了一边这三者之间的关系,并以此记录下来(sdk以Android-24为例)。

首先看一段简短的代码

        HandlerThread handlerThread = new HandlerThread("hai");
        handlerThread.start();
        Handler handler = new Handler(handlerThread.getLooper()) {
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        };
        handler.sendEmptyMessage(1);
代码的功能就是一个系统已经定义好的一个thread,new出来之后启动,然后拿到这个thread 的handler,通过handler发送消息,thread里的looper接收到消息后把消息交给handler处理。ok!代码片段解释到此结束,下面开始分析HandlerThread是如何实现Android系统的handler-looper消息循环机制。

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;

    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
由上看出HandlerThread继承Thread,即它就是一个自定义的Thread。然后handlerThread.start()后线程启动,执行run方法。其实它和自new线程然后在run方法中调用Looper.prepare,Looper.loop 的实现是一个道理

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }
且看Looper.prepare(),sThreadLocal是Looper类加载时就初始化的一个对象

 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));
    }
由sThreadLocal.get()进去
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }
由于新new出来的线程的threadLocals没初始化,所以getMap(t)返回空,因而执行setInitialValue(),

    private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }

 void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

由于getMap(t)==null,因此当前Thread会为自己的threadLocals作一个初始化一个ThreadLocalMap,键就是当前的ThreadLocal,firstValue为null。ThreadLocalMap的作用类似于Map存放键值对。

由于sThreadLocal.get()得到的值为空,因此会sThreadLocal.set(new Looper(quitAllowed)),

    private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
当前线程中new的Looper中初始化了一个MessageQueue和保存了对当前线程的引用。
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }
set(T value)的作用就是把new出来的Looper保存到当前Thread 的 threadLocals变量中。

再通过new Handler(handlerThread.getLooper())就得到了和当前线程Looper关联的Handler。

到此,与此Thread关联的Looper、messageQueue、Handler就此登场了。看看他们两的类图,


下面上重点:looper是如何轮询的?看 Looper.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 (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
Looper通过一个for循环不断的调用queue.next()取message,(这里先说明下,queue.next()不会返回空,除非线程正在退出)

Message next() {
        // Return here if the message loop has already quit and been disposed.
        // This can happen if the application tries to restart a looper after quit
        // which is not supported.
        final long ptr = mPtr;
        if (ptr == 0) {
            return null;
        }

        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        mBlocked = false;
                        if (prevMsg != null) {
                            prevMsg.next = msg.next;
                        } else {
                            mMessages = msg.next;
                        }
                        msg.next = null;
                        if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                        msg.markInUse();
                        return msg;
                    }
                } else {
                    // No more messages.
                    nextPollTimeoutMillis = -1;
                }

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }

从for开始看,它也是一个for循环,每次循环都会nativePollOnce一次(它的作用暂时不知),然后找寻msg,找到则返回,如果messageQueue为空则调用next()方法的线程会一直在此处for循环。一个new的新线程MessageQueue中 mMessages是null,所以线程会一直循环,直到Handler send一个message后,mMessages才不会为空。

一句话总结就是:Thread一直在调用Looper的for循环,而Looper的for循环则一直在调用Messagequeue的for循环,即Thread一直在调用MessageQueue的for循环。

最后说明下UI线程,它也是通过调用Looper.prepareMainLooper()和Looper.looper来实现消息轮询的,具体可以看看ActivityThread的main方法实现。


















猜你喜欢

转载自blog.csdn.net/u014763302/article/details/69250893