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.