您當前的位置:首頁 > 娛樂

Handler中Looper死迴圈為什麼不會導致應用卡死?

作者:由 程式設計師圖書館 發表于 娛樂時間:2020-06-09

歡迎關注專欄:

裡面定期分享Android和Flutter架構技術知識點及解析,還會不斷更新的BATJ面試專題,歡迎大家前來探討交流,如有好的文章也歡迎投稿。

Flutter跨平臺開發終極之選

應用卡死,也就是ANR所產生的原因?

1、5秒鐘之內沒有響應輸入的事件,比如按鍵、螢幕觸控等。

2、廣播接收器在10秒內沒有執行完畢。

為什麼說應用所有的操作都是在loop()中來管理?

首先,我們的每一個應用都存在於自己的虛擬機器中,也就是說每一個應用都有自己的一個main函式,這個main函式就是ActivityThread。java的main()函式。

public static void main(String[] args) {

Trace。traceBegin(Trace。TRACE_TAG_ACTIVITY_MANAGER, “ActivityThreadMain”);

SamplingProfilerIntegration。start();

// CloseGuard defaults to true and can be quite spammy。 We

// disable it here, but selectively enable it later (via

// StrictMode) on debug builds, but using DropBox, not logs。

CloseGuard。setEnabled(false);

Environment。initForCurrentUser();

// Set the reporter for event logging in libcore

EventLogger。setReporter(new EventLoggingReporter());

// Make sure TrustedCertificateStore looks in the right place for CA certificates

final File configDir = Environment。getUserConfigDirectory(UserHandle。myUserId());

TrustedCertificateStore。setDefaultUserDirectory(configDir);

Process。setArgV0(“”);

Looper。prepareMainLooper();

ActivityThread thread = new ActivityThread();

thread。attach(false);

if (sMainThreadHandler == null) {

sMainThreadHandler = thread。getHandler();

}

if (false) {

Looper。myLooper()。setMessageLogging(new

LogPrinter(Log。DEBUG, “ActivityThread”));

}

// End of event ActivityThreadMain。

Trace。traceEnd(Trace。TRACE_TAG_ACTIVITY_MANAGER);

Looper。loop();

throw new RuntimeException(“Main thread loop unexpectedly exited”);

}

為什麼每一個應用會有自己的一個main函式呢?

當我們在launcher介面啟動一個應用的時候,這時候,系統就會用zygote給我們分配一個虛擬機器,然後,這個應用就會執行在這個虛擬機器上面。

應用執行到虛擬機器之後,首先它要執行的就是啟動ActivityThread,在ActivityThread中,它又會啟動它的main()函式。

在main()函式中,它最重要的兩行程式碼:

public static void main(String[] args) {

。。。

Looper。prepareMainLooper();

。。。

Looper。loop();

}

所以在程式執行的時候,主執行緒所有的程式碼都執行在這個Looper裡面。

也就是說應用所有生命週期的函式(包括Activity、Service所有生命週期)都執行在這個Looper裡面,而且,它們都是以訊息的方式存在的。

假如說一個Activity啟動,要走onResume()函式的時候,它就會在Activity的H裡面執行RESUME_ACTIVITY。

case RESUME_ACTIVITY: return “RESUME_ACTIVITY”;

它傳送了一個Resume的訊息,再接著看下這個Resume這個訊息做了什麼事情,程式碼在ActivityThread。java的handleMessage中。

case RESUME_ACTIVITY:

Trace。traceBegin(Trace。TRACE_TAG_ACTIVITY_MANAGER, “activityResume”);

SomeArgs args = (SomeArgs) msg。obj;

handleResumeActivity((IBinder) args。arg1, true, args。argi1 != 0, true,

args。argi3, “RESUME_ACTIVITY”);

Trace。traceEnd(Trace。TRACE_TAG_ACTIVITY_MANAGER);

break;

進入handleResumeActivity()方法。

// TODO Push resumeArgs into the activity for consideration

r = performResumeActivity(token, clearHide, reason);

它觸發了Activity的管理機制,在Activity的管理機制裡面,他就會發送一個訊息,這個訊息,就是對Activity進行Resume的操作。

r。activity。performResume();

接著往performResume()方法裡面走,就進入了Activity。java。

final void performResume() {

。。。。

mFragments。dispatchResume();

mFragments。execPendingActions();

。。。。

}

再後面就呼叫了Fragemet的管理機制。

public void dispatchResume() {

mHost。mFragmentManager。dispatchResume();

}

因為類的繼承,到最終是繼承自了FragmentActivity,所以最後又變成了對Fragment的Resume。

既然Handler的訊息全都是loop來的,為什麼我們沒有ANR問題?

其實產生ANR問題的不是Looper。loop(),哪怕主執行緒正在等待(block)。

for (;;) {

Message msg = queue。next(); // might block

。。。

}

因為這個時候(阻塞)的時候,說明主執行緒在休眠。

之前不是說5秒鐘不相應就會出現阻塞問題嗎,為什麼休眠個好長時間也並不會被ANR呢?

瞭解這個問題,先看喚醒主執行緒的方式有哪些:

1、輸入事件

主執行緒雖然被block了,但與ANR的問題是沒有關係的,只要輸入事件有響應,他會喚醒,就不會被block了。

所以,產生ANR的問題不是因為主執行緒睡眠了,而是因為輸入事件沒有響應,輸入事件沒有響應他就沒有辦法喚醒這個Looper,才加了這個5秒的限制。

2、往Looper裡面新增訊息的時候,它會喚醒這個Looper。

因為應用中不管是Activity,還是Service,所有的操作都是在各自的生命週期中執行的,所以它所有的操作都逃不出生命週期。所以,所有的操作都執行在ActivityThread。java中的loop()裡面,所以,應用所有的操作都是在這個loop()中來管理的,也正是因為這個原因,主執行緒的loop()是不能夠退出去的。

只有一種情況,我們在一個應用的一個介面下不動,這個應用沒有任何事件發生,也沒有任何別的事件要處理,這個時候,我們的Looper就處於一個block狀態;當點選一下這個螢幕,他就會觸發喚醒這個Looper。

總結

為什麼沒有導致應用卡死?

因為應用卡死壓根與這個Looper沒有關係,應用在沒有訊息需要處理的時候,它是在睡眠,釋放執行緒;卡死是ANR,而Looper是睡眠。

卡死是在主執行緒中執行一個耗時的操作,loop()會一直在處理一個訊息,而for迴圈中有很多訊息需要被處理,而這一個訊息就要處理很久,這一個訊息的處理時間,會轉變成其他的點選事件沒有響應。

因為主執行緒在接受到其他訊息的時候沒有時間去響應,它的時間都在處理那一個耗時的操作,造成點選事件沒有辦法響應,點選事件沒有辦法響應就容易出現ANR。

原文作者:Seas。Su

原文連結:

https://

blog。csdn。net/yichen97/

java/article/details/106367067

標簽: Looper  Loop  activity  ANR  main