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.