Android学习笔记--Handler源码

176 阅读3分钟

消息类型

1. 屏障消息

特点

msg.target为空

相关方法
添加屏障

MessageQueue#postSyncBarrier

移除屏障

MessaageQueue#removeSyncBarrier

源码举例
//android.view.ViewRootImpl
void scheduleTraversals() {
    if (!mTraversalScheduled) {
        mTraversalScheduled = true;
        //添加屏障
        //保证后续绘制UI的msg可以被优先执行
        mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
        mChoreographer.postCallback(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
        //...省略代码
    }
}

void unscheduleTraversals() {
    if (mTraversalScheduled) {
        mTraversalScheduled = false;
        //移除屏障
        mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
        mChoreographer.removeCallbacks(
                Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
    }
}

2. 异步消息

特点

msg中flag&FLAG_ASYNCHRONOUS不为0
msg专门提供了两个方法
设置消息类型为异步消息

//android.os.Message
public void setAsynchronous(boolean async) {
    if (async) {
        flags |= FLAG_ASYNCHRONOUS;
    } else {
        flags &= ~FLAG_ASYNCHRONOUS;
    }
}   

设置判断消息类型是否是异步消息

//android.os.Message
public boolean isAsynchronous() {
    return (flags & FLAG_ASYNCHRONOUS) != 0;
}    
源码举例
//android.view.Choreographer
private void postCallbackDelayedInternal(int callbackType,
        Object action, Object token, long delayMillis) {
    synchronized (mLock) {
        final long now = SystemClock.uptimeMillis();
        final long dueTime = now + delayMillis;
        //callback加到链表中
        mCallbackQueues[callbackType].addCallbackLocked(dueTime, action, token);
        //如果到了执行时间,或者过了执行时间,就立刻开始获取VSYNC信号
        if (dueTime <= now) {
            scheduleFrameLocked(now);
        } else {
            //如果还没到执行时间,就设定指定时间执行
            Message msg = mHandler.obtainMessage(MSG_DO_SCHEDULE_CALLBACK, action);
            msg.arg1 = callbackType;
            //设置消息类型为异步消息
            msg.setAsynchronous(true);
            mHandler.sendMessageAtTime(msg, dueTime);
        }
    }
}

3. 同步消息

普通消息,无优先执行权。也即是非屏障消息,非异步消息。

整体逻辑

异步消息需要配合屏障消息使用才会生效。
Android中,系统也会大量使用handler进行线程间的通信。正常情况下,所有的消息按执行时间排序,以单链表的方式存于MessageQueue,但是,有些消息的优先级比较高(比如说屏幕的绘制),我们希望能在指定时间立即执行,就诞生了消息屏障+异步消息。

MessageQueue#next流程图
MessageQueue#next方法流程图.png
源码
//android.os.MessageQueue#next
Message next() {
    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();
        }
        //进行休眠操作
        //参数nextPollTimeoutMillis:
        // 0:不需要休眠;
        // -1:一直休眠,直到被唤醒;
        // >0: 指定时间自动唤醒
        //注意此处for循环,第一次进来nextPollTimeoutMillis必然为0,第二次、第三次for循环,nextPollTimeoutMillis可能为0/-1/大于0的值
        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.
                //如果队首是屏障消息,遍历MessageQueue,找到最早的异步消息
                do {
                    prevMsg = msg;
                    msg = msg.next;
                } while (msg != null && !msg.isAsynchronous());
            }
            if (msg != null) {
                //如果找到了msg
                //对应两种情况:
                //1. 队首不是屏障消息,那msg可能是同步消息,也可能异步消息,此时,不区分是同步还是异步,均按同步消息进行处理
                //2. 队首是屏障消息,那msg必然是异步消息
                if (now < msg.when) {
                    //如果找到的msg还没到执行的时间,那就计算一下休眠时间
                    //等待下一次for循环的时候进行休眠
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {
                    //如果已经到了msg的执行时间
                    mBlocked = false;
                    //把msg从链表中移除
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                        mMessages = msg.next;
                    }
                    msg.next = null;
                    if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                    msg.markInUse();
                    //for循环结束,msg返回给looper,做下一步处理
                    return msg;
                }
            } else {
                //如果没找到msg
                //存在两种情况
                //1. 队首不是屏障消息,那意味着MessageQueue里没有消息,链表是空
                //2. 队首是屏障消息,表示队列里没有异步消息
                //等下一次for循环,nativePollOnce一直休眠
                nextPollTimeoutMillis = -1;
            }

            // Process the quit message now that all pending messages have been handled.
            if (mQuitting) {
                dispose();
                return null;
            }
            //第一次计算IdleHandler的数量
            if (pendingIdleHandlerCount < 0
                    && (mMessages == null || now < mMessages.when)) {
                pendingIdleHandlerCount = mIdleHandlers.size();
            }
            if (pendingIdleHandlerCount <= 0) {
                //没有IdleHandler要处理,就外层的继续for循环
                mBlocked = true;
                continue;
            }

            if (mPendingIdleHandlers == null) {
                mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
            }
            mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
        }

        //遍历设置的IdleHandler
        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 {
                //执行IdleHandler#queueIdle方法
                keep = idler.queueIdle();
            } catch (Throwable t) {
                Log.wtf(TAG, "IdleHandler threw exception", t);
            }
            //IdleHandler#queueIdle方法返回false,表示该idlehandler只需要执行一次
            //把该IdleHandler从列表里移除,下次不再执行
            if (!keep) {
                synchronized (this) {
                    mIdleHandlers.remove(idler);
                }
            }
        }
        //走到这里,说明有IdleHandler,并且已经执行了一遍IdleHandler#queueIdle了
        //那把nextPollTimeoutMillis置为0
        //这样,在下次for循环时,不是直接休眠,而是再看看msg的情况(毕竟IdleHandler#queueIdle执行时间不定,可能出现IdleHandler#queueIdle执行完后,队首的消息状态已经发生了变化)
        pendingIdleHandlerCount = 0;
        nextPollTimeoutMillis = 0;
    }
}

总结

  1. MessageQueue的数据结构是以执行时间排序的单向链表,表头的执行时间最小,最先被处理
  2. 如果MessageQueue的链表队首不是屏障消息,那链表里的异步消息与普通消息无异
  3. 如果屏障消息后面没有异步消息,那在屏障消息移除前,即使没有要执行的异步消息,同步消息(普通消息)都不会被执行(消费)