Android 爲何主線程的looper 一直循環不會ANR

閱讀此文須要對handler原理有必定的瞭解程度。java

Handler 原理和源碼linux

首先貼出來兩個知識點。app

第一 java線程能夠休眠oop

第二Android只有主線程能夠更新UI學習

有人以爲這是傻子都知道的知識,那接下來講傻子可能不知道的知識spa

直接敘述線程

全部java的入口都是main方法 由虛擬機調用,Android 的也不例外,剛開始學習那會根本沒研究Android 從哪裏開始執行的,如今我知道了告訴那些不知道的同窗,不是從application。直接看源碼ActivityThread3d

看到了嗎?看到了吧。對象

再來一個驚天的大冪冪blog

當main 方法執行完畢以後,程序就會退出了。

那不對啊和咱們看到的不同啊,App啓動以後能夠一直運行啊,怎麼解釋。

直接解釋,App一直運行這個是沒錯的,也就是說明main方法並無執行完,看代碼

activityThread的main方法

先看3,若是main方法執行完到最後會拋一個異常,很明顯咱們的App並無拋異常,那就說明Main方法沒有執行完。

那怎麼才能保證不會執行完畢呢?

這個問題就須要思考了,若是讓我作,最早想到的就是開一個死循環,可是時間一長確定就OOM了,

其實Android 也是這麼作的  ,1處的代碼 裏面不給你們看了 大概的邏輯內容我文字帶過

建立一個惟一的Looper 對象,而後綁定一個messageQueue隊列 。(不懂的能夠去看handler 詳解)

而後看2 代碼裏邊就是開啓了Looper循環,一個死循環無限的從消息隊列中去取消息(handler源碼)。

這樣的話咱們的Main方法就卡在這裏了,就不會執行完,程序也就是咱們看到那樣,一直在運行。

剛纔我說了要是我們寫個死循環那估計領導就得找咱們談談理想了,時間一長就OOM了,那爲何Android 能夠這麼搞呢,簡單解釋一下我也不懂也不深究,linux層去實現的,阻塞式循環,也就是有消息了就去執行消息,沒有消息以後主線程就會休眠,前邊說過了 java線程是容許休眠的(有興趣的朋友能夠去單獨深究一下)

到這裏了 若是你明白了這一點,就說明個人敘述能力仍是能夠的(若是沒懂那就多看兩遍,看到懂爲止  哈哈)

主線程在main方法中開了一個阻塞式死循環,保證咱們的程序不會退出。

問題2來了 

說是死循環,可是咱們的App可不是死的,使可以接受交互的。

這裏仍是handler機制的功勞(不懂的能夠去看handler 機制),當咱們一個事件好比說一個點擊、長按、滑動,都會經過handler 把這個事件封裝成一個message 消息,而且放到Looper的死循環隊列當中,這個時候的主線程就會被喚醒,而後對Message進行分發 ,這個時候事件已經被分配到了主線程當中,而後具體去執行,好比toast等等。這就是一個完整的事件處理流程。

那麼問題來了 咱們正常點擊的速度是確定沒有程序執行快的,因此說不會有任何問題,可是若是一個點擊事件當中執行了耗時操做,看下面代碼

  這個點擊了 會ANR嗎?答案是不必定,

第一種狀況,若是隻點擊了一次,主線程休眠十秒,沒有問題,十秒以後主線程執行完畢,繼續阻塞式休眠。

第二種狀況,若是連續點擊了屢次,多個事件放到Looper 對象的MessageQueue當中 ,第一個事件去執行,主線程休眠十秒,而後第二個事件分發過來的時候,主線程還在sleep,這個時候咱們的第二個事件就一直得不到執行,超過閥值就會ANR。

ANR 的緣由 由於Looper對象MessageQueue隊列中的事件沒有可以獲得及時執行。

閥值

按鍵事件 5s ,broadcast 10s、service ANR超時的定義在ActiveServices.java中,前臺service無響應的超時時間爲20秒,後臺service爲200秒

回到主題,Android 主線程looper 一直循環不會ANR

兩個方面回答  第一,死循環不是形成ANR的必然緣由 ,ANR是由於消息隊列當中的事件沒有獲得及時的處理形成的。(可是咱們寫個死循環 基本上就會形成ANR,緣由就是主線程一直在這裏循環 ,後面的事件沒有的到及時處理。 )

第二 主線程的Looper 循環 不會ANR最多就是OOM,爲何不會OOM上邊解釋了

相關文章
相關標籤/搜索