代码基于Android SDK 29
Handler基本原理
子线程使用Handler:首先执行Looper.prepare和Looper.loop。Handler类:
public Handler(@Nullable 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()");
}
}
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
在构造Handler时,对Looper进行判断,如果通过ThreadLocal获取的Looper为空,则报错。Looper类:
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));
}
Looper.prepare创建Looper并设置给ThreadLocal,每个Thread只能有一个Looper,否则异常。Looper.loop开始读取MessageQueue中消息。主线程中ActivityThread.main中调用了这两个方法。
MessageQueue.next()来获取消息,没有消息则阻塞在这里。Looper类:
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;
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
}
}
MessageQueue类:
@UnsupportedAppUsage
Message next() {
for (;;) {
nativePollOnce(ptr, nextPollTimeoutMillis);
}
}
在native侧,最终使用epoll_wait(native中的源码)来进行等待(Linux中epoll机制)。java中的wait/notify也能实现阻塞等待消息功能,Android2.2及以前,就是这样实现的。 www.androidos.net.cn/android/2.1… 后来用select实现android.googlesource.com/platform/fr… 后来用epoll,是由于native侧的事件,只能使用java的wait/notify就不够用。android.googlesource.com/platform/fr…
一个线程只能对应一个Looper对应一个MessageQueue 对应多个Handler。 多个线程给MessageQueue发消息通过加锁保证线程安全。
boolean enqueueMessage(Message msg, long when) {
synchronized (this) {
...
}
}
Handler发送延迟消息:postDelayed-->SendMessageDelayed-->sendMessageAtTime-->enqueueMessage Handler类:
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
return queue.enqueueMessage(msg, uptimeMillis);
}
MessageQueue类:
boolean enqueueMessage(Message msg, long when) {
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 进行顺序排序,将消息插入
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;
}
Handler进行post消息时,在MessageQueue中根据when时长进行顺序排序。
@UnsupportedAppUsage
Message next() {
for (;;) {
// 通过epoll_wait等待消息,等待nextPollTimeoutMillis时长
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;
}
}
- 将传入的延迟时间转化为距离开机时间的毫秒数
- MessageQueue根据上一步转化时间进行顺序排序
- MessageQueue.next获取消息,对比当前时间(noew)和第一步转化的时间(when),如果now<when,则通过epoll_wait的timeout进行等待。
- 如果消息需要等待,进行idel handlers执行,执行完以后再去检查此消息是否可以执行
View.post:
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;
}
如果attachInfo不为空则通过attachInfo的handler执行;如果handler为空,则通过runQueue执行。 ViewRootImpl类:
final ViewRootHandler mHandler = new ViewRootHandler();
public ViewRootImpl(Context context, Display display) {
mAttachInfo = new View.AttachInfo(mWindowSession, mWindow, display, this, mHandler, this,
context);
}
private void performTraversals() {
final View host = mView;
if (mFirst) {
host.dispatchAttachedToWindow(mAttachInfo, 0);
}
}
ViewRootImpl构造函数,创建了mAttachInfo,然后再performTraversals中,如果mFirst为true,则调用host.dispatchAttachedToWindow,host就是DcorView。mAttachInfo的mHandler是ViewRootImpl内部的ViewRootHandler。调用到DecorView.dispatchAttachedToWindow,ViewGroup.ispatchAttachedToWindow,依次调用child对应的ispatchAttachedToWindow方法。把AttachInfo传进去,在子View中给mAttachInfo赋值。 ViewGroup类:
@Override
@UnsupportedAppUsage
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mGroupFlags |= FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
super.dispatchAttachedToWindow(info, visibility);
mGroupFlags &= ~FLAG_PREVENT_DISPATCH_ATTACHED_TO_WINDOW;
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
final View child = children[i];
child.dispatchAttachedToWindow(info,
combineVisibility(visibility, child.getVisibility()));
}
final int transientCount = mTransientIndices == null ? 0 : mTransientIndices.size();
for (int i = 0; i < transientCount; ++i) {
View view = mTransientViews.get(i);
view.dispatchAttachedToWindow(info,
combineVisibility(visibility, view.getVisibility()));
}
}
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
}
attachInfo是ViewRootImpl首次触发performTraversals传进来的,View.post是通过ViewRootImpl内部的Handler处理的。 如果在performTraversals之前或者mAttachInfo置为空以后进行执行,则通过RunQueue处理。HandlerActionQueue类:
public void post(Runnable action) {
postDelayed(action, 0);
}
public void postDelayed(Runnable action, long delayMillis) {
final HandlerAction handlerAction = new HandlerAction(action, delayMillis);
synchronized (this) {
if (mActions == null) {
mActions = new HandlerAction[4];
}
mActions = GrowingArrayUtils.append(mActions, mCount, handlerAction);
mCount++;
}
}
public void executeActions(Handler handler) {
synchronized (this) {
final HandlerAction[] actions = mActions;
for (int i = 0, count = mCount; i < count; i++) {
final HandlerAction handlerAction = actions[i];
handler.postDelayed(handlerAction.action, handlerAction.delay);
}
mActions = null;
mCount = 0;
}
}
getRunQueue().post(action)是将任务放到mAction保存,然后executeActions的时候进行执行。executeActions时机只有一个,dispatchAttachedToWindow里调用的。 View类:
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
void dispatchAttachedToWindow(AttachInfo info, int visibility) {
mAttachInfo = info;
if (mRunQueue != null) {
mRunQueue.executeActions(info.mHandler);
mRunQueue = null;
}
}
View.post和Handler.post区别:
- 如果performTraversals前调用View.post,则将消息保存,之后dispatchAttachedToWindow时通过ViewRootImpl的handler进行调用。
- 如果在performTraversals后调用View.post,则直接通过ViewRootImpl的handler进行调用
View.post的Runnable执行的时候,已经执行过performTraversals,View的measure layout draw 方法都执行过,所以可以获取View的宽高信息。
我们进行UI操作时候,都会调用到ViewRootImpl里。例如requestLayout ViewRootImpl类:
public ViewRootImpl(Context context, Display display) {
mThread = Thread.currentThread();
}
@Override
public void requestLayout() {
if (!mHandlingLayoutInLayoutRequest) {
checkThread();
mLayoutRequested = true;
scheduleTraversals();
}
}
void checkThread() {
if (mThread != Thread.currentThread()) {
throw new CalledFromWrongThreadException(
"Only the original thread that created a view hierarchy can touch its views.");
}
}
其实检查的是当前线程(一般在主线程创建的)。mThread 指的是 ViewRootImpl 创建的线程。因为ViewRootImpl 创建是在主线程创建的,所以在非主线程操作 UI 过不了这里的检查。