平时使用Handler的时候,我们都知道调用了Handler.sendMessage()
方法后,消息会在handleMessage()
中被处理,或者调用了Handler.post()
之后,Runnable
会被在一定的时机下得到执行。但至于什么时候,可能就不会去在意这些细节了。虽然很久前就看过了Handler的机制,但那时候是为了学习而学习,一旦跟实际联系起来就脱节了。比如说:
- 都知道Android的
main
方法在ActivityThread类中,并且在该方法里面调用了Looper.loop();
让主线程进入了死循环,但是我们平时执行的代码也是在主线程的,他们是怎么跳过这个死循环去执行的? - 有时候需要在onCreate方法中做一些延时操作,我们就会利用
Handler.sendMessage()
或者Handler.post()
方法,这样就能将相应的逻辑延迟到onResume
之后了。但这又是如何保证它会延迟到onResume
之后的?
带着这两个问题,重新来学习一下Handler的消息机制。
用一句话来总结Handler的消息机制就是:Looper通过死循环不断地去查询MessageQueue中有没有新的消息,有的话取出来处理,处理之完继续不断的查询....实际上,代码也确实是这样写的。
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
// 在设置了退出标志的时候,这里取出的msg就会为null
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
......
try {
// 让msg对应的Handler去处理消息
msg.target.dispatchMessage(msg);
} finally {
...
}
}
}
需要注意的是,一个线程里面只能有一个Looper,而一个Looper对应着一个MessageQueue。所以在一个线程里面,无论你有多少个Handler,最终发送的消息都要在同一个MessageQueue中排队等待被执行。
Handler无非就是往MessageQueue中发送消息而已,而MessageQueu的任务就是接收Handler的消息,并接受Looper的查询而已(简单点来理解就好了。)
到了这里,勉强算是又重温了一遍Handler的消息机制,再来看一下第一个问题,先看看ActivityThread的main
方法:
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
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");
}
Looper.loop()
方法之后是一个异常,也就是说,如果我们的代码跳出了Looper的循环,程序也就挂了,而这个循环又和我们的onCreate
一样是在主线程中执行的,那么就剩下一种可能了,我们平时执行的代码就是在Looper.loop()
中去执行的,loop
方法我们也看了,就是从消息队列中取出消息然后去处理消息。也就是说,其它线程通过主线程的Handler来发送Message,从而让Message在主线程中去处理的。从main
方法可以看出消息不可能是在主线程中发出的。为了验证我们的猜想,可以在Activity的onCreate
中打个断点,看看是从哪里回调过来的,如下图:
从上图可以很清楚的看到onCreate
方法确实是在Looper.loop()
中去执行的,也验证了我们的猜想。到这里,第一个问题也就解了,Looper.loop()
方法将主线程阻塞住了,然后系统通过Handler的方式在loop()
中去处理我们的各种回调。
再来看第二个问题,为什么在onCreate
方法中调用Handler.post()
方法会等到onResume()
之后才被执行。从第一个问题我们知道,onCreate
方法是在一个消息中去处理的。那其实有两种可能,一种是在执行我们的post
方法之前,插入了一个消息去处理onResume
事件,又或者是onCreate
和onResume
本身就在同一个消息中。
根据上图中的方法调用栈,去ActivityThread源码中看一下handleLaunchActivity
方法,这里只给出部分代码而已。
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
.......
Activity a = performLaunchActivity(r, customIntent);
if (a != null) {
r.createdConfig = new Configuration(mConfiguration);
reportSizeConfigurations(r);
Bundle oldState = r.state;
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
.....
} else {
.....
}
}
performLaunchActivity
方法最终会调用到onCreate
方法,这从调用栈中可以很明显的看出来。而从名字上看handleResumeActivity
,这里最后很有可能会调用到onResume
方法,具体流程怎么样,不用跟进去看,毕竟源码我们不熟,只需在onResume
方法中打个断点即可验证我们的猜想。
从调用栈中可以看出,onCreate
和onResume
方法是在同一个消息中被处理的,所以无论你是在onCreate
,onStart
,还是在onResume
中用Handler往MessageQeue中发送消息,最终都至少要在onResume
之后才被执行到。所以我们可以利用这个特点来做一些需要延迟的操作。
到这里,文章开头的两个问题也就都解决了,从这两个问题上,也算是对Handler的机制有了更进一步的理解。