目录

总览

Message

Obtain - 获取对象

Recycle

Asynchronous - 异步

MessageQueue

enqueueMessage函数详解

next函数详解

barrier详解

postSyncBarrier函数解读

removeSyncBarrier函数解读

IdleHandler解读

FileDescriptor介绍

Handler

dispatchMessage & handleMessage 函数详解

SendMessageXXX函数详解

RemoveMessage函数介绍

Looper

prepare函数详解 

loop函数详解

MainLooper


总览

画图工具:https://www.draw.io/ 

看完之后画个图,便于理解:

Message

官方文档:https://developer.android.com/reference/android/os/Message

Defines a message containing a description and arbitrary data object that can be sent to a Handler. This object contains two extra int fields and an extra object field that allow you to not do allocations in many cases.

While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.

虽然消息的构造函数是公共的,但构建消息对象的最佳方法是调用Message.obtain()或其中一个Handler.obtainMessage()方法,这将从消息池(链表)中获取已回收的消息对象。

Obtain - 获取对象

注意警告里的话,最好的构建消息的方式是调用Message.obtain(),或者Handler.obtainMessage() ,会复用已经回收的消息。

所有的Message构造函数最终都会调用obtain()函数,我们来看看源码:

注意:从全局的消息链表返回一个消息体,避免经常去new一个新的实例。(这个有可能会造成内存泄漏)

/** * Return a new Message instance from the global pool. Allows us to * avoid allocating new objects in many cases. *  * 从一个全局的池子里返回一个Message实例。让我们在各种情况下,避免去分配新的对象。 */public static Message obtain() {    synchronized (sPoolSync) {        // 如果sPool非等于null,则把sPool返回,m.next赋值给sPool,并减少sPoolSize        if (sPool != null) {            Message m = sPool;            sPool = m.next;            m.next = null;            m.flags = 0; // clear in-use flag            sPoolSize--;            return m;        }    }    // 如果sPool为null,则new一个message    return new Message();}

看到这里会有些困惑,sPool是什么鬼?next又是什么鬼???

我们继续往下看,recycleUnchecked()函数。

Recycle

/** * Recycles a Message that may be in-use. * Used internally by the MessageQueue and Looper when disposing of queued Messages. */void recycleUnchecked() {    // Mark the message as in use while it remains in the recycled object pool.    // Clear out all other details.    flags = FLAG_IN_USE;    what = 0;    arg1 = 0;    arg2 = 0;    obj = null;    replyTo = null;    sendingUid = -1;    when = 0;    target = null;    callback = null;    data = null;    synchronized (sPoolSync) {        // 把sPool赋值给next,把当前的消息对象赋值给了sPool。于是当有消息回收时,sPool就非等于null了。        if (sPoolSize < MAX_POOL_SIZE) {            next = sPool;            sPool = this;            sPoolSize++;        }    }}

我们再看看这几个变量的定义:

// sometimes we store linked lists of these things// 通过next成员变量简单实现LinkedList,而sPool是一个全局的消息实例,处于链表的最末端。/*package*/ Message next;private static final Object sPoolSync = new Object();private static Message sPool;private static int sPoolSize = 0;// 链表(或者说消息池)的最大size是50。private static final int MAX_POOL_SIZE = 50;

Asynchronous - 异步

ChoreographerpostCallbackDelayedInternal()函数里,看到msg.setAsynchronous(true);这样一行代码。

说实话,当时我的是懵逼的,根本不知道Message还分同步和异步。

首先我们还是来看源码&注解肯定会有疑惑,请继续看下一章:MessageQueue

/** * Sets whether the message is asynchronous, meaning that it is not * subject to {@link Looper} synchronization barriers. * 

* Certain operations, such as view invalidation, may introduce synchronization * barriers into the {@link Looper}'s message queue to prevent subsequent messages * from being delivered until some condition is met. In the case of view invalidation, * messages which are posted after a call to {@link android.view.View#invalidate} * are suspended by means of a synchronization barrier until the next frame is * ready to be drawn. The synchronization barrier ensures that the invalidation * request is completely handled before resuming. *

* Asynchronous messages are exempt from synchronization barriers. They typically * represent interrupts, input events, and other signals that must be handled independently * even while other work has been suspended. *

* Note that asynchronous messages may be delivered out of order with respect to * synchronous messages although they are always delivered in order among themselves. * If the relative order of these messages matters then they probably should not be * asynchronous in the first place. Use with caution. *

* * @param async True if the message is asynchronous. * * @see #isAsynchronous() * 设置消息是否是异步的,这意味着它不受Looper同步消息拦截器(barriers)的影响。 * * 某些操作(例如视图失效),可能会在Looper的MessageQueue引入同步拦截器,用来阻碍后续同步消息的分发,直到某些情况的出现。 * * 在视图失效的情况下,调用invalidate后分发的消息,会被同步拦截器suspend,直到下一帧准备好了为止。 * * 同步拦截器确保invalidation请求在恢复之前会被完全处理。 * * 异步消息不受同步拦截器的影响。他们通常表示必须独立处理的中断,输入事件和其他信号,即使其他工作已暂停。 * * 请注意,异步消息可能无序传递,同步消息虽然它们总是按顺序分发。 * 如果这些消息的顺序很重要,那么首先它们可能不应该是异步的。 * 谨慎使用异步。 */public void setAsynchronous(boolean async) { if (async) { flags |= FLAG_ASYNCHRONOUS; } else { flags &= ~FLAG_ASYNCHRONOUS; }}

MessageQueue

官方文档:https://developer.android.com/reference/android/os/MessageQueue

MessageQueue类由若干函数、1个内部类和2个接口组成。

Low-level class holding the list of messages to be dispatched by a Looper. Messages are not added directly to a MessageQueue, but rather through Handler objects associated with the Looper.

You can retrieve the MessageQueue for the current thread with Looper.myQueue().

Android的底层类,包含由Looper分发的消息列表。消息不会直接添加到MessageQueue,而是通过与Looper关联的Handler对象添加。

你可以通过Looper.myQueue()来获取当前线程的MessageQueue。

enqueueMessage函数详解

handler调用,sendMessageXXX()函数,最终都会调用MessageQueueenqueueMessage()方法。

具体可见:Handler

boolean enqueueMessage(Message msg, long when) {    // msg没有target则抛出异常    if (msg.target == null) {        throw new IllegalArgumentException("Message must have a target.");    }    // msg正在使用,则抛出异常    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;        // 如果当前消息队列为空 或 新消息 需要立即分发 或 新消息 的when小于当前消息队列的第一个消息的when,则需要插入到队列头部。        if (p == null || when == 0 || when < p.when) {            // New head, wake up the event queue if blocked.            msg.next = p;            mMessages = msg;            // 如果当前队列被block住了,则需要唤醒            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.            // 将 新消息 插入队列的中间,通常我们不会去唤醒这个事件队列,除非在队列头部有一个拦截器,并且这个 新消息 是队列中最早的异步消息。            // 1. mBlocked // Indicates whether next() is blocked waiting in pollOnce() with a non-zero timeout.            // 表示next()是否被阻塞在pollOnce()中等待非零超时。            // 我们再来看看什么时候mBlocked会被赋值,在next()函数里,有消息会被置false;如果没有消息了并且没有没有idle handlers需要执行,则会置true。            // 2. p.target == null            // 代表着队列头部有一个拦截器,后文会分析postSyncBarrier()代码。            // 3. msg.isAsynchronous()            // 新消息是否为异步消息            needWake = mBlocked && p.target == null && msg.isAsynchronous();            Message prev;            for (;;) {                // 遍历当前队列中所有的消息,找到新消息的when比队列中消息的when小的消息,插入在这个消息之前;否则则插入到队列尾部。                prev = p;                p = p.next;                if (p == null || when < p.when) {                    break;                }                // 如果队列有早于新消息的异步消息,则needWake为false。(判断是否需要唤醒)                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.        // 因为mQuitting是false,所以我们可以认为mPtr != 0。判断是否需要唤醒事件队列,如果要唤醒则调用nativeWake(mPtr)。        if (needWake) {            nativeWake(mPtr);        }    }    return true;}

next函数详解

MessageQueuenext()函数会在Looperloop()里调用。

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.    // mPtr是native层的消息队列指针,nativeInit()返回    final long ptr = mPtr;    if (ptr == 0) {        return null;    }    int pendingIdleHandlerCount = -1; // -1 only during first iteration    int nextPollTimeoutMillis = 0; // 首次进入函数,阻塞立即返回    // 死循环,renturn msg 或 消息队列退出    // 由于MessageQueue对象由Looper持有,线程join之前,调用looper quit    for (;;) {         if (nextPollTimeoutMillis != 0) {            Binder.flushPendingCommands();        }        // 阻塞等待函数,nextPollTimeoutMillis -1为无限等待,0为立即返回,>0超时返回        // 具体可以看看https://www.kancloud.cn/alex_wsc/android-deep2/413394        // 最终调用的是epoll_wait        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.                // 消息队列头部有barrier,则不处理同步消息,查找队列中的异步消息进行处理                do {                    prevMsg = msg;                    msg = msg.next;                } while (msg != null && !msg.isAsynchronous());            }            if (msg != null) {                // 找到了可待处理msg                if (now < msg.when) {                    // 下一条消息还没有到处理时间,设置一个超时,这个超时针对的是之前的nativePollOnce函数                    // 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.                    // 拿到了一个message                    mBlocked = false;                    if (prevMsg != null) {                        // 这里处理的异步消息,将它从队列中移除                        prevMsg.next = msg.next;                    } else {                        // 这里处理的是队列头部(没有barrier)的第一个消息                        mMessages = msg.next;                    }                    msg.next = null;                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);                    msg.markInUse();                    return msg;                }            } else {                // No more messages.                // 如果没有message,则设置为无限等待,也是针对nativePollOnce函数                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.            // idle Handler逻辑,当前消息队列空了,或者第一个消息需要在将来被处理(也许是因为barrier),则执行idle handler回调            if (pendingIdleHandlerCount < 0                    && (mMessages == null || now < mMessages.when)) {                pendingIdleHandlerCount = mIdleHandlers.size();            }            if (pendingIdleHandlerCount <= 0) {                // 如果没有idleHandler,则设置线程block,并且继续循环                // 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.        // 处理idleHandler回调        // queueIdle如果返回true则保持该idleHandler        // 如果返回false,则处理完之后remove        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.        // 处理完idle handler,可能会有新的消息被分发,所以这里不阻塞,立即返回        nextPollTimeoutMillis = 0;    }}

barrier详解

同步拦截器,主要有2个函数,postSyncBarrier()removeSyncBarrier()

postSyncBarrier函数解读

在消息队列中添加一个同步的拦截器。

private int postSyncBarrier(long when) {    // Enqueue a new sync barrier token.    // We don't need to wake the queue because the purpose of a barrier is to stall it.    synchronized (this) {        final int token = mNextBarrierToken++;        // 这里调用obtain函数,注意target是null,        // 这也是为什么enqueueMessage和next函数会用msg.target == null判断是否为barrier的原因。        final Message msg = Message.obtain();         msg.markInUse();        msg.when = when;        msg.arg1 = token;        Message prev = null;        Message p = mMessages;        // 这里的when传入的是SystemClock.uptimeMillis()        if (when != 0) {            // 遍历寻找队列中消息p,p.when > when(when前面的消息还是要处理的)            while (p != null && p.when <= when) {                prev = p;                p = p.next;            }        }        // 如果找到了消息p,则把barrier消息插入prev和p之间        if (prev != null) { // invariant: p == prev.next            msg.next = p;            prev.next = msg;        } else { // 如果没有找到p,则把barrier消息插入队列头部            msg.next = p;            mMessages = msg;        }        // 返回token(用于标识)        return token;    }}

removeSyncBarrier函数解读

在消息队列中移除一个消息拦截器。

/** * Removes a synchronization barrier. * * @param token The synchronization barrier token that was returned by * {@link #postSyncBarrier}. * * @throws IllegalStateException if the barrier was not found. * * @hide */public void removeSyncBarrier(int token) {    // Remove a sync barrier token from the queue.    // If the queue is no longer stalled by a barrier then wake it.    synchronized (this) {        Message prev = null;        Message p = mMessages;        // 遍历消息队列,寻找token为标识的barrier message        while (p != null && (p.target != null || p.arg1 != token)) {            prev = p;            p = p.next;        }        // 如果没有找到barrier msg,则抛出异常        if (p == null) {            throw new IllegalStateException("The specified message queue synchronization "                    + " barrier token has not been posted or has already been removed.");        }        final boolean needWake;        // 1.如果barrier msg在队列中间,直接移除barrier,并且不需要唤醒        // 2.如果barrier msg在队列头部,当前消息直接指向下一个msg,并且判断是否需要唤醒队列        if (prev != null) {            prev.next = p.next;            needWake = false;        } else {            mMessages = p.next;            needWake = mMessages == null || mMessages.target != null;        }        p.recycleUnchecked();        // If the loop is quitting then it is already awake.        // We can assume mPtr != 0 when mQuitting is false.        if (needWake && !mQuitting) {            nativeWake(mPtr);        }    }}

IdleHandler解读

顾名思义:这个handler会在消息队列空闲的时候,去做某些事情。

主要涉及addIdleHandler()removeIdleHandler()两个函数。

以及一个接口:

/** * Callback interface for discovering when a thread is going to block * waiting for more messages. */public static interface IdleHandler {    /**     * Called when the message queue has run out of messages and will now     * wait for more.  Return true to keep your idle handler active, false     * to have it removed.  This may be called if there are still messages     * pending in the queue, but they are all scheduled to be dispatched     * after the current time.     */    boolean queueIdle();}

具体怎么用呢???

打个比方,如果你想在Activity渲染完成后做某些事情,你可以在onCreate函数里这样写:

@Overridepublic void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    Looper.getMainLooper().getQueue().addIdleHandler(new MessageQueue.IdleHandler() {        @Override        public boolean queueIdle() {            // TO DO            return false;        }    });}

FileDescriptor介绍

可以监听文件描述符的状态,这个还没有具体使用过,稍后再看吧。

Handler

官方文档:https://developer.android.com/reference/android/os/Handler

dispatchMessage & handleMessage 函数详解

dispatchMessage()函数由Looper调用。

public void dispatchMessage(Message msg) {    if (msg.callback != null) { // 判断是否有Runnable,直接调用run()。        handleCallback(msg);    } else {        if (mCallback != null) {            // 判断当前handler是否有mCallback,直接调用mCallback的handleMessage()函数,可以让具有相同callback的handler统一处理消息。            if (mCallback.handleMessage(msg)) {                return;            }        }        // 调用当前handler的handleMessage()函数。        handleMessage(msg);    }}

SendMessageXXX函数详解

Handler类中有数个sendMessageXXX()以及postXXX()函数,包括post()函数。(API 28)

作用:MessageQueue消息队列添加消息。以当前的系统时间,或延迟时间去被执行。

调用图谱如下:

RemoveMessage函数介绍

顾名思义,将未处理的MessageRunnableMessageQueue中移除。

ActivityFragment生命周期结束时,记得移除未处理的MessageRunnable,避免占用消息队列、造成内存泄漏等问题,提升性能。

Looper

官方文档:https://developer.android.com/reference/android/os/Looper

Class used to run a message loop for a thread. Threads by default do not have a message loop associated with them; to create one, call prepare() in the thread that is to run the loop, and then loop() to have it process messages until the loop is stopped.

用于为线程运行消息循环的类。默认情况下,线程是没有一个与之关联的消息循环;可以在线程的run()方法中调用loop的prepare()函数来创建一个,然后就可以在loop()函数就可以开始处理消息了,直到消息循环停止。具体可以查看HandlerThread代码。

prepare函数详解 

为当前线程初始化一个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));  }

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.    // 这里调用了2次clearCallingIdentity,为了确保获取线程token一定是当前本地进程的,而非IPC调用的pid和uid    // 后面我们看看clearCallingIdentity的源码便于理解    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.            // 如果没有消息返回,则代表message queue退出了。            // 因为next函数会阻塞,所以可以这么判断            return;        }        // This must be in a local variable, in case a UI event sets the logger        // 可以使用setMessageLogging来设置mLogging变量,输出日志        final Printer logging = me.mLogging;        if (logging != null) {            logging.println(">>>>> Dispatching to " + msg.target + " " +                    msg.callback + ": " + msg.what);        }        // dispatch的阈值,可以监控卡顿,但是setSlowDispatchThresholdMs是hide方法。        final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;        // 跟踪打印message被处理的信息        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);            }        }        // >0 且 处理时长大于阈值,则打印出来相关信息        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.        // 确保在消息的分发处理过程中,线程的token没有被破坏。        final long newIdent = Binder.clearCallingIdentity();        if (ident != newIdent) {            // 如果破坏了,则打印warning级别的log            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();    }}

这里列出clearCallingIdentity()的代码,也就理解了为什么loop()那里需要调用2次,才能确保获取到的是当前进程的线程token。

int64_t IPCThreadState::clearCallingIdentity(){    int64_t token = ((int64_t)mCallingUid<<32) | mCallingPid;    clearCaller();    return token;}void IPCThreadState::clearCaller(){    mCallingPid = getpid();    mCallingUid = getuid();}

MainLooper

Application主线程的looper。

/** * Initialize the current thread as a looper, marking it as an * application's main looper. The main looper for your application * is created by the Android environment, so you should never need * to call this function yourself.  See also: {@link #prepare()} */public static void prepareMainLooper() {    prepare(false);    synchronized (Looper.class) {        if (sMainLooper != null) {            throw new IllegalStateException("The main Looper has already been prepared.");        }        sMainLooper = myLooper();    }}/** * Returns the application's main looper, which lives in the main thread of the application. */public static Looper getMainLooper() {    synchronized (Looper.class) {        return sMainLooper;    }}

 

更多相关文章

  1. Android第十二课 jni函数的静态绑定
  2. 关于Handler.removemessages方法
  3. Android(安卓)Vibrator 框架总结
  4. Android消息机制——时钟显示和异步处理工具类(AsyncTask)
  5. Android(安卓)-- CursorAdapter
  6. Android(安卓)输入系统解析 (2)
  7. ARM cortex A8/9 - Android(安卓)NDK - NEON介绍以及优化
  8. Android:Handler中的Idle Handler
  9. Android(安卓)4.4KitKat AudioFlinger 流程分析

随机推荐

  1. Android脚本语言环境 SL4A
  2. 平安科技移动开发二队技术周报(第十三期)
  3. 2017年11月1日Android职位数据分析
  4. 史上最全的android studio 插件大全整理
  5. Android之ActionBar学习
  6. 在Android Studio中使用Wifi连接Android
  7. 安卓boot recovery解包打包
  8. android 适配
  9. Android中基于NuPlayer的RTSP框架学习
  10. AIDL实现进程间通信