本文的目标是来剖析下 Android 零碎中以 Handler、Looper、MessageQueue 组成的异步音讯解决机制,通过源码来理解整个音讯解决流程的走向以及相干三者之间的关系

须要先理解以下几个基本概念

  • Handler:主线程或者子线程通过 Handler 向 MessageQueue(音讯队列) 发送 Message,以此来触发定时工作或者更新 UI
  • MessageQueue:通过 Handler 发送的音讯并非是立刻执行的,须要存入音讯队列中来顺次执行,音讯队列中的工作按照音讯的优先级高下(延时工夫的长短)来程序寄存
  • Looper:Looper 用于从 MessageQueue 中循环获取音讯并将之传递给音讯解决者(即音讯发送者 Handler 自身)来进行解决,每条 Message 都有个 target 变量用来指向音讯的发送者自身,以此把 Message 和其解决者关联起来
  • 互斥机制:可能会有多条线程(1条 UI 线程,n 条子线程)同时向同一个音讯队列插入音讯,此时就须要有同步机制来保障音讯的有序性以防止竞态

先从开发者日常的应用办法作为入口,以此来剖析其整个流程的走向

Handler 发送音讯的模式次要有以下几个办法,不论其是否是延时工作,其最终调用的都是 sendMessageAtTime() 办法

    public final boolean sendMessage(Message msg){        return sendMessageDelayed(msg, 0);    }    public final boolean post(Runnable r){       return  sendMessageDelayed(getPostMessage(r), 0);    }    public final boolean sendMessageDelayed(Message msg, long delayMillis){        if (delayMillis < 0) {            delayMillis = 0;        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    }

sendMessageAtTime() 办法中须要一个已初始化的 MessageQueue 类型的全局变量 mQueue,否则程序无奈持续走上来

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

而 mQueue 变量是在构造函数中进行初始化的,且 mQueue 是成员常量,这阐明 Handler 与 MessageQueue 是一一对应的关系,不可更改

如果构造函数没有传入 Looper 参数,则会默认应用以后线程关联的 Looper 对象,mQueue 须要依赖于从 Looper 对象中获取,如果 Looper 对象为 null ,则会间接抛出异样,且从异样信息 Can't create handler inside thread that has not called Looper.prepare() 中能够看到,在向 Handler 发送音讯前,须要先调用 Looper.prepare()

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

走进 Looper 类中,能够看到,myLooper() 办法是从 sThreadLocal 对象中获取 Looper 对象的,sThreadLocal 对象又是通过 prepare(boolean) 来进行赋值的,且该办法只容许调用一次,一个线程只能创立一个 Looper 对象,否则将抛出异样

      static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();        public static @Nullable Looper myLooper() {        return sThreadLocal.get();    }    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));    }

此处除了因为prepare(boolean)屡次调用会抛出异样导致无奈关联多个 Looper 外,Looper 类的构造函数也是公有的,且在构造函数中还初始化了一个线程常量 mThread,这都阐明了 Looper 只能关联到一个线程,且关联之后不能扭转

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

那么 Looper.prepare(boolean) 办法又是在哪里调用的呢?查找该办法的所有援用,能够发现在 Looper 类中有如下办法,从名字来看,能够猜想该办法是由主线程来调用的,查找其援用

    public static void prepareMainLooper() {        prepare(false);        synchronized (Looper.class) {            if (sMainLooper != null) {                throw new IllegalStateException("The main Looper has already been prepared.");            }            sMainLooper = myLooper();        }    }

最初定位到 ActivityThread 类的 main() 办法

看到 main() 函数的办法签名,能够晓得该办法就是一个利用的起始点,即当利用启动时, 零碎就主动为咱们在主线程做好了 Handler 的初始化操作, 因而在主线程里咱们能够间接应用 Handler

如果是在子线程中创立 Handler ,则须要咱们手动来调用 Looper.prepare() 办法

    public static void main(String[] args) {        ···        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        // End of event ActivityThreadMain.        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }

回到最开始,既然 Looper 对象曾经由零碎来为咱们初始化好了,那咱们就能够从中失去 mQueue对象

    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()");        }        //获取 MessageQueue 对象        mQueue = mLooper.mQueue;        mCallback = callback;        mAsynchronous = async;    }

mQueue 又是在 Looper 类的构造函数中初始化的,且 mQueue 是 Looper 类的成员常量,这阐明 Looper 与 MessageQueue 是一一对应的关系

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

sendMessageAtTime() 办法中在解决 Message 时,最终调用的是 enqueueMessage() 办法

当中,须要留神 msg.target = this 这句代码,target 对象指向了发送音讯的主体,即 Handler 对象自身,即由 Handler 对象发给 MessageQueue 的音讯最初还是要交由 Handler 对象自身来解决

    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);    }    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {        //target 对象指向的也是发送音讯的主体,即 Handler 对象        //即由 Handler 对象发给 MessageQueue 的音讯最初还是要交由 Handler 对象自身来解决        msg.target = this;        if (mAsynchronous) {            msg.setAsynchronous(true);        }        return queue.enqueueMessage(msg, uptimeMillis);    }

因为存在多个线程同时往同一个 Loop 线程的 MessageQueue 中插入音讯的可能,所以 enqueueMessage() 外部须要进行同步。能够看出 MessageQueue 外部是以链表的构造来存储 Message 的(Message.next),依据 Message 的延时工夫的长短来将决定其在音讯队列中的地位

mMessages 代表的是音讯队列中的第一条音讯,如果 mMessages 为空,阐明音讯队列是空的,或者 mMessages 的触发工夫要比新音讯晚,则将新音讯插入音讯队列的头部;如果 mMessages 不为空,则寻找音讯列队中第一条触发工夫比新音讯晚的非空音讯,并将新音讯插到该音讯后面

到此,一个依照解决工夫进行排序的音讯队列就实现了,后边要做的就是从音讯队列中顺次取出音讯进行解决了

boolean enqueueMessage(Message msg, long when) {        //Message 必须有解决者        if (msg.target == null) {            throw new IllegalArgumentException("Message must have a target.");        }        if (msg.isInUse()) {            throw new IllegalStateException(msg + " This message is already in use.");        }        synchronized (this) {            if (mQuitting) {                IllegalStateException e = new IllegalStateException(                        msg.target + " sending message to a Handler on a dead thread");                Log.w(TAG, e.getMessage(), e);                msg.recycle();                return false;            }            msg.markInUse();            msg.when = when;            Message p = mMessages;            boolean needWake;            //如果音讯队列是空的或者队列中第一条的音讯的触发工夫要比新音讯长,则将新音讯作为链表头部            if (p == null || when == 0 || when < p.when) {                // New head, wake up the event queue if blocked.                msg.next = p;                mMessages = msg;                needWake = mBlocked;            } else {                // Inserted within the middle of the queue.  Usually we don't have to wake                // up the event queue unless there is a barrier at the head of the queue                // and the message is the earliest asynchronous message in the queue.                needWake = mBlocked && p.target == null && msg.isAsynchronous();                Message prev;                //寻找音讯列队中第一条触发工夫比新音讯晚的音讯,并将新音讯插到该音讯后面                for (;;) {                    prev = p;                    p = p.next;                    if (p == null || when < p.when) {                        break;                    }                    if (needWake && p.isAsynchronous()) {                        needWake = false;                    }                }                msg.next = p; // invariant: p == prev.next                prev.next = msg;            }            // We can assume mPtr != 0 because mQuitting is false.            if (needWake) {                nativeWake(mPtr);            }        }        return true;    }

上面再看下 MessageQueue 是如何读取 Message 并回调给 Handler 的

在 MessageQueue 中音讯的读取其实是通过外部的 next() 办法进行的,next() 办法是一个有限循环的办法,如果音讯队列中没有音讯,则该办法会始终阻塞,当有新音讯来的时候 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;                }                if (mPendingIdleHandlers == null) {                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];                }                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);            }            // Run the idle handlers.            // We only ever reach this code block during the first iteration.            for (int i = 0; i < pendingIdleHandlerCount; i++) {                final IdleHandler idler = mPendingIdleHandlers[i];                mPendingIdleHandlers[i] = null; // release the reference to the handler                boolean keep = false;                try {                    keep = idler.queueIdle();                } catch (Throwable t) {                    Log.wtf(TAG, "IdleHandler threw exception", t);                }                if (!keep) {                    synchronized (this) {                        mIdleHandlers.remove(idler);                    }                }            }            // Reset the idle handler count to 0 so we do not run them again.            pendingIdleHandlerCount = 0;            // While calling an idle handler, a new message could have been delivered            // so go back and look again for a pending message without waiting.            nextPollTimeoutMillis = 0;        }    }

next() 办法又是通过 Looper 类的 loop() 办法来循环调用的,而 loop() 办法也是一个有限循环,惟一跳出循环的条件就是 queue.next() 办法返回为null ,仔细的读者可能曾经发现了,loop() 就是在 ActivityThread 的 main()函数中调用的

因为 next() 办法是一个阻塞操作,所以当没有音讯也会导致 loop() 办法一只阻塞着,而当 MessageQueue 一中有了新的音讯,Looper 就会及时地解决这条音讯并调用 Message.target.dispatchMessage(Message) 办法将音讯传回给 Handler 进行解决

/**     * 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 (;;) {            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 slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;            final long traceTag = me.mTraceTag;            if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {                Trace.traceBegin(traceTag, msg.target.getTraceName(msg));            }            final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();            final long end;            try {                msg.target.dispatchMessage(msg);                end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();            } finally {                if (traceTag != 0) {                    Trace.traceEnd(traceTag);                }            }            if (slowDispatchThresholdMs > 0) {                final long time = end - start;                if (time > slowDispatchThresholdMs) {                    Slog.w(TAG, "Dispatch took " + time + "ms on "                            + Thread.currentThread().getName() + ", h=" +                            msg.target + " cb=" + msg.callback + " msg=" + msg.what);                }            }            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();        }    }

看下 Handler 对象解决音讯的办法

    /**     * Handle system messages here.     */    public void dispatchMessage(Message msg) {        if (msg.callback != null) {            handleCallback(msg);        } else {            if (mCallback != null) {                if (mCallback.handleMessage(msg)) {                    return;                }            }            handleMessage(msg);        }    }

如果 msg.callback 不为 null ,则调用 callback 对象的 run() 办法,该 callback 实际上就是一个 Runnable 对象,对应的是 Handler 对象的 post() 办法

    private static void handleCallback(Message message) {        message.callback.run();    }
    public final boolean post(Runnable r){       return  sendMessageDelayed(getPostMessage(r), 0);    }    private static Message getPostMessage(Runnable r) {        Message m = Message.obtain();        m.callback = r;        return m;    }

如果 mCallback 不为 null ,则通过该回调接口来解决音讯,如果在初始化 Handler 对象时没有通过构造函数传入 Callback 回调接口,则交由 handleMessage(Message) 办法来解决音讯,咱们个别也是通过重写 Handler 的 handleMessage(Message) 办法来解决音讯

最初来总结下以上的内容

  1. 在创立 Handler 实例时要么为构造函数提供一个 Looper 实例,要么默认应用以后线程关联的 Looper 对象,如果以后线程没有关联的 Looper 对象,则会导致抛出异样
  2. Looper 与 Thread ,Looper 与 MessageQueue 都是一一对应的关系,在关联后无奈更改,但 Handler 与 Looper 能够是多对一的关系
  3. Handler 能用于更新 UI 有个前提条件:Handler 与主线程关联在了一起。在主线程中初始化的 Handler 会默认与主线程绑定在一起,所以尔后在解决 Message 时,handleMessage(Message msg) 办法的所在线程就是主线程,因而 Handler 能用于更新 UI
  4. 能够创立关联到另一个线程 Looper 的 Handler,只有本线程可能拿到另外一个线程的 Looper 实例
        new Thread("Thread_1") {            @Override            public void run() {                Looper.prepare();                final Looper looper = Looper.myLooper();                new Thread("Thread_2") {                    @Override                    public void run() {                        Handler handler = new Handler(looper);                        handler.post(new Runnable() {                            @Override                            public void run() {                                //输入后果是:Thread_1                                Log.e(TAG, Thread.currentThread().getName());                            }                        });                    }                }.start();                Looper.loop();            }        }.start();

最初

对于如何学习Android Framework开发常识,最近小编有幸在某大厂技术总监手里扒到这份Android Framework高级开发笔记,局部常识章节公布到了在知乎上居然1000+点赞,明天就拿进去分享给大家。

本笔记次要解说了Framework的次要模块:

第一章: 深刻解析Binder

Binder机制作为过程间通信的一种伎俩,基本上贯通了andorid框架层的全副。所以首先必须要搞懂的Android Binder的根本通信机制。  
本章知识点

  • Binder 系列—开篇
  • Binder Driver 初探
  • Binder Driver 再探
  • Binder 启动 ServiceManager
  • 获取 ServiceManager
  • 注册服务(addService)
  • 获取服务(getService)
  • Framework 层剖析
  • 如何应用 Binder
  • 如何应用 AIDL
  • Binder 总结
  • Binder 面试题全解析

第二章: 深刻解析Handler

置信大家都有这样的感触:网上剖析 Handler 机制原理的文章那么多, 为啥还要画龙点睛整顿这份笔记呢?不是说前人们写的文章不好,我就是感觉他们写的不细, 有些点不讲清楚,逻辑很难通顺的,每次我学个什么货色时遇到这种状况都贼好受。

本章先宏观实践剖析与 Message 源码剖析,再到MessageQueue 的源码剖析,Looper 的源码剖析,handler 的源码剖析,Handler 机制实现原理总结。最初还整顿Handler 所有面试题大全解析。

Handler这章内容很长,但思路是循序渐进的,如果你能保持读完我置信必定不会让你悲观。

因为篇幅无限,仅展现局部内容,有须要的敌人【点击我】收费获取。

第三章: Dalvik VM 过程零碎

Andorid系统启动、init 过程、Zygote、SystemServer启动流程、 应用程序的创立应用,Activity的创立、销毁 Handler和Looper。

第四章深刻解析 WMS

窗口治理框架 零碎动画框架 View的工作原理。

第五块 PackagerManagerService

包治理服务。 资源管理相干类

因为篇幅无限,仅展现局部内容,有须要的敌人【点击我】收费获取。