1.引言
众所周知在Activity的主线程中不能做耗时操作,但是 查看ActivityThread的源码可以看到,该线程中包含了一个Loop.looper()的阻塞操作,那么该阻塞操作为何不会引起ANR?
2.源码分析
其实引起ANR的原因主要包括以下两点:
1.当前的事件没有机会得到处理(即主线程正在处理当前事件,没有及时完成或looper中的事件分发处理被阻塞);
2.当前事件正在执行,但没有及时完成。
为了避免ANR的产生,安卓中引入了Handler的处理机制,通过查看ActivtyThread的源码可以看出:
public static final void main(String[] args) {
...
//创建Looper和MessageQueue
Looper.prepareMainLooper();
...
//开始轮询
Looper.loop();
...
}
查看Looper.loop()方法,该方法的操作与我们熟悉的Handelr处理机制类似,分为两步操作:取出消息和分发消息。
while (true) {
//取出消息队列中的消息
Message msg = queue.next(); // might block
...
/根据Message中的target标签,交给对应的Handle处理
msg.target.dispatchMessage(msg);
...
}
因此在ActivityThread的main方法中主要是做消息的循环操作,一旦退出该循环操作,那么当前应用就退出了。
但是该死循环是在主线程中操作,为何不会引起ANR呢?
通过查看ActivityThread的handleMessage的源码可以看出,Android是由事件驱动的,常见的触摸和Activity的生命周期都是运行在Looper.loop()的控制之下,如果该循环停止了,那么整个应用也停止了。
public void handleMessage(Message msg) {
if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));
switch (msg.what) {
case LAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
final ActivityClientRecord r = (ActivityClientRecord) msg.obj;
r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);
handleLaunchActivity(r, null);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
break;
case RELAUNCH_ACTIVITY: {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");
ActivityClientRecord r = (ActivityClientRecord) msg.obj;
handleRelaunchActivity(r);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
break;
case PAUSE_ACTIVITY:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder) msg.obj, false, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 2) != 0);
maybeSnapshot();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
case PAUSE_ACTIVITY_FINISHING:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");
handlePauseActivity((IBinder) msg.obj, true, (msg.arg1 & 1) != 0, msg.arg2, (msg.arg1 & 1) != 0);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...........
}
}
通过查看上面的源码可以看出Activity的整个生命周期都是依靠Looper.loop(),在不同的生命周期执行时发送不同的消息,handleMessage接收到不同的Message后,根据case判断进行相应的处理。
由于Activty的执行是遵循一定的生命周期方法的,因此如果某个周期的方法做过多的耗时操作,必然会影响下个周期的执行时间,整个生命周期的执行就会出现卡顿,继而会产生ANR的出现。
并且主线的Looper对于消息的处理时,当子线程有消息发送时才会被唤醒,但子线程没有消息发送时,处于待唤醒状态,因此不会对CPU的性能产生影响。
3.总结
因此:主线程的Looper.loop()中死循环本身不会对Activity产生ANR,除非其消息事件本身的处理存在耗时操作,才会产生ANR.
欢迎关注晓涵说(CSDN)、xukang868(github)账号信息,查看更多文章。
网友评论