Android面試:主線程中的Looper.loop()一直無限循環(huán)為什么不會造成ANR?

引子:

正如我們所知胧奔,在android中如果主線程中進行耗時操作會引發(fā)ANR(Application Not Responding)異常。

造成ANR的原因一般有兩種:

  1. 當前的事件沒有機會得到處理(即主線程正在處理前一個事件预吆,沒有及時的完成或者looper被某種原因阻塞住了)
  2. 當前的事件正在處理龙填,但沒有及時完成

為了避免ANR異常,android使用了Handler消息處理機制拐叉。讓耗時操作在子線程運行岩遗。

因此產生了一個問題,主線程中的Looper.loop()一直無限循環(huán)檢測消息隊列中是否有新消息為什么不會造成ANR凤瘦?

本人面試網易的時候就被問到了T_T

源碼分析

ActivityThread.java 是主線程入口的類宿礁,這里你可以看到寫Java程序中司空見慣的main方法,而main方法正是整個Java程序的入口蔬芥。

ActivityThread源碼

    public static final void main(String[] args) {
        ...
        //創(chuàng)建Looper和MessageQueue
        Looper.prepareMainLooper();
        ...
        //輪詢器開始輪詢
        Looper.loop();
        ...
    }

Looper.loop()方法

   while (true) {
       //取出消息隊列的消息梆靖,可能會阻塞
       Message msg = queue.next(); // might block
       ...
       //解析消息,分發(fā)消息
       msg.target.dispatchMessage(msg);
       ...
    }

顯而易見的笔诵,如果main方法中沒有l(wèi)ooper進行循環(huán)返吻,那么主線程一運行完畢就會退出。這還玩?zhèn)€蛋昂跣觥测僵!

總結:ActivityThread的main方法主要就是做消息循環(huán),一旦退出消息循環(huán)谢翎,那么你的應用也就退出了捍靠。


我們知道了消息循環(huán)的必要性,那為什么這個死循環(huán)不會造成ANR異常呢岳服?

因為Android 的是由事件驅動的剂公,looper.loop() 不斷地接收事件、處理事件吊宋,每一個點擊觸摸或者說Activity的生命周期都是運行在 Looper.loop() 的控制之下纲辽,如果它停止了颜武,應用也就停止了。只能是某一個消息或者說對消息的處理阻塞了 Looper.loop()拖吼,而不是 Looper.loop() 阻塞它鳞上。

也就說我們的代碼其實就是在這個循環(huán)里面去執(zhí)行的,當然不會阻塞了吊档。

handleMessage方法部分源碼

 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篙议,當收到不同Message時則采用相應措施。

如果某個消息處理時間過長怠硼,比如你在onCreate(),onResume()里面處理耗時操作鬼贱,那么下一次的消息比如用戶的點擊事件不能處理了,整個循環(huán)就會產生卡頓香璃,時間一長就成了ANR这难。

讓我們再看一遍造成ANR的原因,你可能就懂了葡秒。

造成ANR的原因一般有兩種:

  1. 當前的事件沒有機會得到處理(即主線程正在處理前一個事件姻乓,沒有及時的完成或者looper被某種原因阻塞住了)
  2. 當前的事件正在處理,但沒有及時完成

而且主線程Looper從消息隊列讀取消息眯牧,當讀完所有消息時蹋岩,主線程阻塞。子線程往消息隊列發(fā)送消息学少,并且往管道文件寫數據剪个,主線程即被喚醒,從管道文件讀取數據版确,主線程被喚醒只是為了讀取消息禁偎,當消息讀取完畢,再次睡眠阀坏。因此loop的循環(huán)并不會對CPU性能有過多的消耗。

總結:Looer.loop()方法可能會引起主線程的阻塞笆檀,但只要它的消息循環(huán)沒有被阻塞忌堂,能一直處理事件就不會產生ANR異常。

參考
https://www.zhihu.com/question/34652589

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末酗洒,一起剝皮案震驚了整個濱河市士修,隨后出現的幾起案子,更是在濱河造成了極大的恐慌樱衷,老刑警劉巖棋嘲,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異矩桂,居然都是意外死亡沸移,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雹锣,“玉大人网沾,你說我怎么就攤上這事∪锞簦” “怎么了辉哥?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長攒射。 經常有香客問我醋旦,道長,這世上最難降的妖魔是什么会放? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任饲齐,我火速辦了婚禮,結果婚禮上鸦概,老公的妹妹穿的比我還像新娘箩张。我一直安慰自己,他們只是感情好窗市,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布先慷。 她就那樣靜靜地躺著,像睡著了一般咨察。 火紅的嫁衣襯著肌膚如雪论熙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天摄狱,我揣著相機與錄音脓诡,去河邊找鬼。 笑死媒役,一個胖子當著我的面吹牛祝谚,可吹牛的內容都是我干的。 我是一名探鬼主播酣衷,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼交惯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了穿仪?” 一聲冷哼從身側響起席爽,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啊片,沒想到半個月后只锻,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡紫谷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年齐饮,在試婚紗的時候發(fā)現自己被綠了捐寥。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡沈矿,死狀恐怖上真,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情羹膳,我是刑警寧澤睡互,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站陵像,受9級特大地震影響就珠,放射性物質發(fā)生泄漏。R本人自食惡果不足惜醒颖,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一妻怎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泞歉,春花似錦逼侦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至挺庞,卻和暖如春晰赞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背选侨。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工掖鱼, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人援制。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓戏挡,卻偏偏與公主長得像,于是被迫代替她去往敵國和親晨仑。 傳聞我的和親對象是個殘疾皇子增拥,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

推薦閱讀更多精彩內容