我们知道,Handler有postDelayed()/post()等API,在UI线程中,通过默认构造方法new Handler(),会创建一个与当前线程的Looper绑定的Handler对象,UI线程的消息循环是由框架层打开(Looper.loop()),APP开发者无需关注。维护一个挂在UI线程的Handler成员变量用以发消息/处理消息,是惯常的代码风格。
当然,还有另外一类API:View.postDelayed()/post()。Android官方文档介绍这类API也是向UI线程发消息,Runnable执行在UI线程中。与Handler.postDelayed()/post()一样,View.postDelayed()/post()的API Level是1,是非常古老的API。
1. View.postDelayed()/post()在 框架层的实现原理
本文源代码分析基于Android 7.1。从View的源代码说起:
/**
* <p>Causes the Runnable to be added to the message queue.
* The runnable will be run on the user interface thread.</p>
*
* @param action The Runnable that will be executed.
*
* @return Returns true if the Runnable was successfully placed in to the
* message queue. Returns false on failure, usually because the
* looper processing the message queue is exiting.
*
* @see #postDelayed
* @see #removeCallbacks
*/
public boolean post(Runnable action) {
final AttachInfo attachInfo = mAttachInfo;
if (attachInfo != null) {
return attachInfo.mHandler.post(action);
}
// Postpone the runnable until we know on which thread it needs to run.
// Assume that the runnable will be successfully placed after attach.
getRunQueue().post(action);
return true;
}
很清楚的两路逻辑:
(1)如果View的成员变量mAttachInfo不为null,直接post到mAttachInfo.mHandler。
(2)如果View的成员变量mAttachInfo为null,post到自身的一个runnable队列中。
1.1 post到mAttachInfo.mHandler
View的成员变量mAttachInfo对应的类是View的一个内部final类:
/**
* A set of information given to a view when it is attached to its parent
* window.
*/
final static class AttachInfo {
... }
在Android的框架层设计中,View需要附着在某个Window上,AttachInfo这个类显然是用于处理View的附着相关的信息。从它的构造方法可以看到关键的一些信息成员变量,其中也看到了mHandler
/**
* Creates a new set of attachment information with the specified
* events handler and thread.
*
* @param handler the events handler the view must use
*/
AttachInfo(IWindowSession session, IWindow window, Display display,
ViewRootImpl viewRootImpl, Handler handler, Callbacks effectPlayer) {
mSession = session;
mWindow = window;
mWindowToken = window.asBinder();
mDisplay = display;
mViewRootImpl = viewRootImpl;
mHandler = handler;
mRootCallbacks = effectPlayer;
}
View的成员变量mAttachInfo在什么地方被赋值?很清晰,在View.dispatchAttachedToWindow()/dispatchDetachedFromWindow():
/**
* @param info the {@link android.view.View.AttachInfo} to associated with
* this view
*/