天天看點

主線程中的Looper.loop()一直無限循環為什麼不會造成ANR?

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.

繼續閱讀