Android 消息机制分析(基于最新源码)

写在前面

此篇文章基于任玉刚老师《Android 开发艺术探索》一书中的第十章节-Android 的消息机制,

并基于 Android 最新源码深入理解,旨在将 Android 消息机制讲透吃透,如果你能静下心来把这篇文章看完,

并且把里面的知识点看懂看会,相信你会对于 Android 消息机制有更加系统的认识,

另,末学才疏学浅,如文中有不妥之处,望不吝赐教。

ThreadLocal 的工作原理

ThreadLocal 是一个线程内部的数据存储类,通常它可以在指定的线程中存储数据。

数据存储之后,只有在指定的线程中可以获取到存储的数据,对于其他线程来说则获取不到。

官方简介:

This class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable. ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).

public class ThreadLocal extends Object

2. ThreadLocal 的使用场景

  • 当某些数据是以线程为作用域,并且不同线程具有不同的数据副本时。
  • 复杂逻辑下的对象传递,表现为函数调用栈比较深以及代码入口的多样性,比如监听器传递。

3.ThreadLocal 使用举例

首先定义一个 ThreadLocal 对象,选定为 boolean 类型

private ThreadLocal<Boolean> threadLocal = new ThreadLocal<Boolean>();

然后分别在主线程,子线程1和子线程2设置和访问它

        threadLocal.set(true);
        Log.d(TAG, "[Thread#main]threadLocal = " + threadLocal.get());

        new Thread("Thread#1") {
            @Override
            public void run() {
                threadLocal.set(false);
                Log.d(TAG, "[Thread#1]threadLocal = " + threadLocal.get());
            }
        }.start();

        new Thread("Thread#2") {
            @Override
            public void run() {
                Log.d(TAG, "[Thread#2]threadLocal = " + threadLocal.get());
            }
        }.start();

看一下日志

D/MainActivity: [Thread#main]threadLocal = true
D/MainActivity: [Thread#1]threadLocal = false
D/MainActivity: [Thread#2]threadLocal = null

果然,虽然在不同线程访问的是同一个 ThreadLocal 对象,获取的值却是不同的。

4. 内部实现

根据 ThreadLocal 的特性,我们推测不同线程访问其 get 方法时,它内部会在各自的进程中取出一个数组,

然后再从数组中根据当前 ThreadLocal 的索引去找出相应的 value。

Talk is cheap, show me the code!

好!看一下源码。

4.1 set 方法

首先看一下 set 方法

    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

首先通过 getMap 方法得到当前线程中的 ThreadLocalMap 对象,

而ThreadLocalMap 是 ThreadLocal 中的内部类,看下这个方法

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

此方法是返回线程中的 threadLocals 对象,到 Thread 中找下相关定义

 ThreadLocal.ThreadLocalMap threadLocals = null;

看到这就明白了,Thread 类内部有一个成员专门存储 ThreadLocaL 的数据,它的类型是 ThreadLocalMap。

那接下来就简单了,如果这个对象是 null 就需要使用 createMap 方法对其初始化,看下代码

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

其实这个逻辑,是 null 就创建一个 ThreadLocalMap, 不是就给它赋值。

那么我们深入 ThreadLocalMap 类探究一下其 set 方法

        /**
         * Set the value associated with key.
         *
         * @param key the thread local object
         * @param value the value to be set
         */
        private void set(ThreadLocal<?> key, Object value) {
            // We don't use a fast path as with get() because it is at
            // least as common to use set() to create new entries as
            // it is to replace existing ones, in which case, a fast
            // path would fail more often than not.
            Entry[] tab = table;
            int len = tab.length;
            int i = key.threadLocalHashCode & (len-1);
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                ThreadLocal<?> k = e.get();
                if (k == key) {
                    e.value = value;
                    return;
                }
                if (k == null) {
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            tab[i] = new Entry(key, value);
            int sz = ++size;
            if (!cleanSomeSlots(i, sz) && sz >= threshold)
                rehash();
        }

上面的注释很明确,这个方法是用于关联 key 与 value 的。

上述代码实现了数据的存储过程,可以看到主要操作是面向 table 的,这是什么呢?

其实在 ThreadLocalMap 中有一个数组

private Entry[] table;

ThreadLocal 的值就存储在其中。

4.2 get 方法

接着分析一下 ThreadLocal 的 get 方法

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

首先也是取出当前线程的内部 ThreadLocalMap,判断它是不是 null,

如果是 null,返回初始值,此初始值由 setInitialValue 方法描述,看下实现

     /**
     * Variant of set() to establish initialValue. Used instead
     * of set() in case user has overridden the set() method.
     *
     * @return the initial value
     */
    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;
    }

和 set 的代码比较像,看下 initialValue

 protected T initialValue() {
        return null;
    }

绕了一大圈又回来了,总结起来其实就是如果 ThreadLocalMap 是 null,

就用 null 值初始化这个 ThreadLocalMap,并返回这个 null 值。

那我们继续看,如果它不是 null,会调用一个 getEntry 方法

        private Entry getEntry(ThreadLocal<?> key) {
            int i = key.threadLocalHashCode & (table.length - 1);
            Entry e = table[i];
            if (e != null && e.get() == key)
                return e;
            else
                return getEntryAfterMiss(key, i, e);
        }

意思就是根据 key 找到对应的内部 table 里的 value,

接着返回了这个 value。

4.3 总结

从 ThreadLocal 的 set 与 get 方法中可以看出,

他们所操作的对象都是当前线程的 threadLocals 对象中的 table 数组,

因此在不同的线程中访问同一个 ThreadLocal 的 set 与 get 方法,他们所做的操作仅限于线程内部,

这就是为什么在多个线程中可以互不干扰地存储和修改数据。

MessageQueue 的工作原理

1. MessageQueue 简介

在 Android 中,MessageQueue 指的是消息队列,其主要包含两个操作,即是插入读取

读取操作本身会会伴随着删除操作,插入和读取对应的方法分别为 enqueueMessagenext

其中 enqueueMessage 的作用是往消息队列中插入一条消息,而 next 是从消息队列中取出一条消息并将其从消息队列中移除。

尽管 MessageQueue 叫做消息队列,它的内部实现却不是队列,实际上它是通过单链表来维护消息列表的。

2. 源码分析

2.1 enqueueMessage 方法
     boolean enqueueMessage(Message msg, long when) {
        ...
        synchronized (this) {
            ...
            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;
    }

从实现来看,其主要操作就是单链表的插入操作。

2.2 next 方法

接着看一下 next 方法

    Message next() {
        ...
        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;
                }
                ...
            }
            ...
        }
    }

这里发现这是一个无限循环的方法,如果消息队列中没有消息,next 方法会一直阻塞在这里,

有消息时其就会返回这条消息并将其从单链表中删除。

2.3 quit 方法
void quit(boolean safe) {
        if (!mQuitAllowed) {
            throw new IllegalStateException("Main thread not allowed to quit.");
        }
        synchronized (this) {
            if (mQuitting) {
                return;
            }
            mQuitting = true;
            if (safe) {
                removeAllFutureMessagesLocked();
            } else {
                removeAllMessagesLocked();
            }
            // We can assume mPtr != 0 because mQuitting was previously false.
            nativeWake(mPtr);
        }
    }

Looper 的工作原理

1. Looper 简介

Looper 在 Android 的消息机制中扮演着消息循环的角色,

简言之其不停从 MessageQueue 中查看是否有新消息,如果有就会立刻处理,否则会一直阻塞。

2. 创建 Looper

Handler 的工作需要 Looper,如果线程不具备 Looper 就会报错,那么如何为一个进程创建 Looper?

答案十分简单

        new Thread("Thread#2") {
            @Override
            public void run() {
                Looper.prepare();
                Handler handler = new Handler();
                Looper.loop();
            }
        }.start();

那么,个中方法是怎样运行的呢?

3. 源码分析

3.1 构造函数

我们先看一下创建一个 Looper 做了什么工作

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

很明显,Looper 创建了一个 MessageQueue,并将当前的线程保存了下来。

3.2 prepare 方法

当我们调用 prepare 方法时,做了哪些事情呢

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    /** Initialize the current thread as a looper.
      * This gives you a chance to create handlers that then reference
      * this looper, before actually starting the loop. Be sure to call
      * {@link #loop()} after calling this method, and end it by calling
      * {@link #quit()}.
      */
    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));
    }

就是在当前进程中的 threadLocal 中设置了一个 Looper 对象,

结合 ThreadLocal 的特性,以及 Handler 的用途,有没有想到 Handler 为什么需要 Loop?

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

此方法也是一个死循环,如果 MessageQueue 的 next 方法返回了新消息,Looper 就会处理这条消息,

  msg.target.dispatchMessage(msg);

这里 target 是发送消息的 Handler 对象,这样 Handler 发送的消息最终又交给 dispatchMessage 处理了,

不同的是,此方法是在创建 Handler 时所用的 Looper 中执行的,这样代码就切换到其他线程了。

唯一退出循环的地方是 MessageQueue 的 next 方法返回了 null。

3.4 quit 方法

这是什么时机呢?很简单,当 Looper 的 quit 方法被调用以后,

    /**
     * Quits the looper.
     * <p>
     * Causes the {@link #loop} method to terminate without processing any
     * more messages in the message queue.
     * </p><p>
     * Any attempt to post messages to the queue after the looper is asked to quit will fail.
     * For example, the {@link Handler#sendMessage(Message)} method will return false.
     * </p><p class="note">
     * Using this method may be unsafe because some messages may not be delivered
     * before the looper terminates.  Consider using {@link #quitSafely} instead to ensure
     * that all pending work is completed in an orderly manner.
     * </p>
     *
     * @see #quitSafely
     */
    public void quit() {
        mQueue.quit(false);
    }

可以看到,这里调用 MessageQueue 的 quit 方法通知消息队列退出,此时 next 方法会返回 null。

3.5 总结

研究源码发现,Looper 与 MessageQueue 联系密切。

loop 方法调用 MessageQueue 的 next 方法获取新消息,而 next 是一个阻塞操作,

如果没有消息,next 会一直阻塞到那里,这导致 loop 方法也一直阻塞。

如果 MessageQueue 的 next 方法返回了新消息,Looper 就会处理这条消息。

Handler 的工作原理

Handler的工作主要是信息的发送和接收工作,发送是 post 一系列以及 send 一系列方法,

其中 post 方法最终是通过 send 来实现的。

1. 构造方法

看一下 Handler 默认构造方法

    /**
     * Default constructor associates this handler with the {@link Looper} for the
     * current thread.
     *
     * If this thread does not have a looper, this handler won't be able to receive messages
     * so an exception is thrown.
     */
    public Handler() {
        this(null, false);
    }

显然,这个方法会调用另一个构造方法

    /**
     * Use the {@link Looper} for the current thread with the specified callback interface
     * and set whether the handler should be asynchronous.
     *
     * Handlers are synchronous by default unless this constructor is used to make
     * one that is strictly asynchronous.
     *
     * Asynchronous messages represent interrupts or events that do not require global ordering
     * with respect to synchronous messages.  Asynchronous messages are not subject to
     * the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
     *
     * @param callback The callback interface in which to handle messages, or null.
     * @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
     * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
     *
     * @hide
     */
    public Handler(Callback callback, boolean async) {
        ...
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

很显然,如果当前线程没有 Looper,就会抛出异常,

这样就解释了在没有 Looper 的子线程中创建 Handle 会引起程序异常的原因。

2. sendMessage 方法

我们看下这个方法是如何实现的:

    /**
     * Pushes a message onto the end of the message queue after all pending messages
     * before the current time. It will be received in {@link #handleMessage},
     * in the thread attached to this handler.
     *  
     * @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.
     */
    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

    /**
     * Enqueue a message into the message queue after all pending messages
     * before (current time + delayMillis). You will receive it in
     * {@link #handleMessage}, in the thread attached to this handler.
     *  
     * @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 final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

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

     private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        return queue.enqueueMessage(msg, uptimeMillis);
    }

可以发现,这一过程仅仅是向消息队列中插入一条消息,

MessageQueue 的 next 方法就会返回这条消息给 Looper,Looper 收到消息后就会开始处理了。

3. dispatchMessage 方法

最终消息会由 Looper 交给 Handler 处理,即 diapatchMessage 方法,这时 Handler 就进入了处理消息的阶段。

处理消息的过程如下:

先检查 Message 的 callback 是否为 null,callback 是一个 Runnable 对象,

实际是 Handler 的 post 方法传递的 Runnable 参数,

callback 不为 null 就会通过 handlerCallback 处理信息:

其次,检查 mCallback 是否为 null,这里看一下 mCallback 定义

final Callback mCallback;

这里的 Callback 是一个 Handler 中定义的接口


    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     */
    public interface Callback {
        /**
         * @param msg A {@link android.os.Message Message} object
         * @return True if no further handling is desired
         */
        public boolean handleMessage(Message msg);
    }

此接口的意义何在呢?

注释中已经在做了说明,可以用来创建一个 Handler 的实例但并不需要派生 Handler 的子类。

日常开发中,创建一个 Handler 的方法无非是派生一个子类并改写其 handlerMessage 方法,

Callback给我们提供了另一种使用 Handler 的方式,例如

Handler handler = new Handler(callback);

那接着往下看,最后调用了 Handler 的 handlerMessage 方法处理消息,整个流程就到此结束了。

主线程的消息循环

主线程就是 ActivityThread,其入口方法是 main,

    public static void main(String[] args) {
        ...
        Process.setArgV0("<pre-initialized>");
        Looper.prepareMainLooper();
        // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
        // It will be in the format "seq=114"
        long startSeq = 0;
        if (args != null) {
            for (int i = args.length - 1; i >= 0; --i) {
                if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                    startSeq = Long.parseLong(
                            args[i].substring(PROC_START_SEQ_IDENT.length()));
                }
            }
        }
        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);
        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");
    }
    // ------------------ Regular JNI ------------------------
    private native void nDumpGraphicsInfo(FileDescriptor fd);
}

可以看到,此方法通过 Looper.prepareMainLooper 方法创建了 Looper 及 MessageQueue,

并通过 Looper.loop 开启了主线程的消息循环,这很好地解释了为什么主线程中默认就可以使用 Handler。

主线程开始之后,ActivityThread 还需要一个 Handler 来和消息队列交互,

    class H extends Handler {
        public static final int BIND_APPLICATION        = 110;
        public static final int EXIT_APPLICATION        = 111;
        public static final int RECEIVER                = 113;
        public static final int CREATE_SERVICE          = 114;
        public static final int SERVICE_ARGS            = 115;
        public static final int STOP_SERVICE            = 116;
        public static final int CONFIGURATION_CHANGED   = 118;
        public static final int CLEAN_UP_CONTEXT        = 119;
        public static final int GC_WHEN_IDLE            = 120;
        public static final int BIND_SERVICE            = 121;
        public static final int UNBIND_SERVICE          = 122;
        public static final int DUMP_SERVICE            = 123;
        public static final int LOW_MEMORY              = 124;
        public static final int PROFILER_CONTROL        = 127;
        public static final int CREATE_BACKUP_AGENT     = 128;
        public static final int DESTROY_BACKUP_AGENT    = 129;
        public static final int SUICIDE                 = 130;
        public static final int REMOVE_PROVIDER         = 131;
        public static final int ENABLE_JIT              = 132;
        public static final int DISPATCH_PACKAGE_BROADCAST = 133;
        public static final int SCHEDULE_CRASH          = 134;
        public static final int DUMP_HEAP               = 135;
        public static final int DUMP_ACTIVITY           = 136;
        public static final int SLEEPING                = 137;
        public static final int SET_CORE_SETTINGS       = 138;
        public static final int UPDATE_PACKAGE_COMPATIBILITY_INFO = 139;
        public static final int DUMP_PROVIDER           = 141;
        public static final int UNSTABLE_PROVIDER_DIED  = 142;
        public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
        public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
        public static final int INSTALL_PROVIDER        = 145;
        public static final int ON_NEW_ACTIVITY_OPTIONS = 146;
        public static final int ENTER_ANIMATION_COMPLETE = 149;
        public static final int START_BINDER_TRACKING = 150;
        public static final int STOP_BINDER_TRACKING_AND_DUMP = 151;
        public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
        public static final int ATTACH_AGENT = 155;
        public static final int APPLICATION_INFO_CHANGED = 156;
        public static final int RUN_ISOLATED_ENTRY_POINT = 158;
        public static final int EXECUTE_TRANSACTION = 159;
        public static final int RELAUNCH_ACTIVITY = 160;
        ...
    }

这就是 ActivityThread.H,内部定义了一组消息类型,主要包括四大组件的启动停止等过程。

ActivityThread 通过 ApplicationThread 和 AMS 进行进程间通信,

AMS 以进程间通信的方式完成 ActivityThread 的请求后回调 ActivityThread 的 Bindler 方法,

然后 ApplicationThread 会向 H 发送消息,H 收到消息就将 ApplicationThread 中的逻辑切换到 ActivityThread,

这个过程就是主线程的消息循环模型。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值