深入Android的学习,肯定会接触到Android的消息机制,对Android消息机制的全盘了解会更容易回答标题的疑问。
Looper.loop()
著名的ActivityThread.main()方法中,倒数第二行代码就是Looper.loop(),Looper.loop()开启了消息循环,深入进去看看代码:
public static void loop() {
//注释1
final Looper me = myLooper();
... ...
//注释2
final MessageQueue queue = me.mQueue;
... ...
//注释3
for (;;) {
... ...
}
}
注释1:获取Looper对象---想要深入了解这一部分,需要深入学习一下ThreadLocal的实现机制;
注释2:从Looper中获取消息队列;
注释3:开启消息循环,就是我们常说的死循环。
阻塞、唤醒
for (;;) {
Message msg = queue.next(); // might block
从代码来看,死循环第一行调用了消息队列的next()方法,并且注释说“might block”,可能会阻塞,这里需要深入看下这个next()方法---MessageQueue.next()
Message next() {
... ...
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//注释1
nativePollOnce(ptr, nextPollTimeoutMillis);
注释1:在该方法中,有一开始出现了一行native方法 , 当没有消息入队的时候,nativePollOnce会阻塞在这里。
这里继续解释一下,nextPollTimeoutMillis如果为0表示阻塞,如果nextPollTimeoutMillis=-1会一直阻塞,一直阻塞到被唤醒。
什么时候被唤醒?我们知道在消息机制中,如果有消息入队就会处理消息,那深入到入队看看,MessageQueue.enqueueMessage()
boolean enqueueMessage(Message msg, long when) {
... ...
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
//注释1
nativeWake(mPtr);
}
}
return true;
}
注释1:从字面意思很容易看出这里是唤醒的意思。(老外的代码很容易被理解,这也是9.0就算很多被禁了,也能很容易从c++层面看到哪里可以入手,哈哈~~)
知道了阻塞和唤醒的具体调用位置,也需要知道在native层面如何实现,这里的就进一步讲到epoll机制。大概的意思就是在epool_wait时一直阻塞着会释放CPU的占用,这也是为什么这个死循环不占用高CPU的原因。(PS:androidxref.com 在先阅读源码,赶快行动起来)
另外,消息机制中还有一个延时入队的实现,也需要了解一下。
ANR相关
先看一段代码,在ProcessRecord.appNotResponding大概最后的位置
if (mService.mUiHandler != null) {
// Bring up the infamous App Not Responding dialog
Message msg = Message.obtain();
msg.what = ActivityManagerService.SHOW_NOT_RESPONDING_UI_MSG;
msg.obj = new AppNotRespondingDialog.Data(this, aInfo, aboveSystem);
mService.mUiHandler.sendMessage(msg);
}
从官方给出的注释来看可以App Not Responding 也就是我们常说的ANR的来源。
几年前面试Android岗位有时候也会问,有哪些ANR,分别对应的时间是多少?(那是多美好的时代!!)
这里看看源码来找到对应的AtivityManagerService中代码片段
// How long we allow a receiver to run before giving up on it.
static final int BROADCAST_FG_TIMEOUT = 10*1000;
static final int BROADCAST_BG_TIMEOUT = 60*1000;
ActiveServices.java
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20*1000;
// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
// How long the startForegroundService() grace period is to get around to
// calling startForeground() before we ANR + stop it.
static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
当然还有ContentPorvider等设置,所以看了源码这些内容也就很清晰的得到了答案。
关于ANR 我们还需要了解如何查找、如何读取等 ,也需要总结ANR的产生原因。
总结
从上面的分析来看,Looper的死循环是一种消息机制,ANR是整个Android大体系下的一个小模块的消息处理的响应方式。两者并没有什么关系,所以在主线程中的Looper会不会导致ANR。