Android進階;Handler訊息機制詳解
我們知道,Android裡面的執行緒做了這樣的分工:主執行緒不做耗時操作,子執行緒不更新UI。
這是因為Android系統是個單執行緒模型,系統給App分配的程式裡,只有一個主執行緒,主執行緒是App程式的核心,所有的元件都在主執行緒裡實現、排程和管理,元件的繪製、互動操作和生命週期回撥都是主執行緒處理的,這個執行緒如果出現阻塞、或多執行緒死鎖、或CPU飢餓,導致事件處理時間過長,甚至沒有機會得到處理,系統就會處理為ANR,強制關閉App。
所以主執行緒不能做耗時操作,耗時操作需要我們在子執行緒裡處理。同時,Android不允許子執行緒重新整理UI,因為Android無法保證多個執行緒同步操作,這樣子執行緒和主執行緒之間就需要做協調,比如子執行緒從網路伺服器拿來資料要展示到UI,就需要告知主執行緒去向UI裡重新整理資料,這就需要Handler訊息機制了。
主執行緒、Looper和訊息佇列
Handler訊息機制是圍繞一個訊息佇列展開的,系統啟動App時,App程式會啟動ActivityThread主執行緒,主執行緒啟動時,會建立一個Looper來迴圈處理訊息,ActivityThread的main函式主要就是讓這個Looper做死迴圈,如果訊息迴圈停止了,App也就停止了:
//ActivityThread原始碼
Looper.loop();
//主執行緒會一直loop,如果出了looper,就直接拋異常,關閉app
throw new RuntimeException("Main thread loop unexpectedly exited");
Looper自己會去建立和管理一個訊息佇列,然後就開始不斷地處理佇列裡的訊息,子執行緒向訊息佇列裡發訊息,就可以和主執行緒通訊了。
訊息佇列為空時,主執行緒會休眠,釋放CPU資源。(主執行緒大部分時間都在休眠)
但是,Android為了確保主執行緒安全,Looper的訊息佇列是ThreadLocal的,禁止其他執行緒訪問,所以子執行緒不能直接向訊息佇列裡發訊息。
這樣,就需要在主執行緒裡放一個Handler,Handler在建立時,會引用所線上程的Looper,進而獲得Looper中的訊息佇列,這樣,我們就可以用Handler來幫忙處理訊息了。
這樣一來,處理訊息的主力就是Handler了。
Message
為了配合Handler,Message裡面有這樣幾個主要屬性:
- what:int值,存放訊息ID(Send方式)
- callback:Runnable物件(Post方式,所以如果訊息的callback非空,就直接處理runnable)
- target:Handler物件,指向Handler(訊息還是丟給Handler處理)
- data: Bundle物件,存放業務資料
- next:Message物件,存放佇列中的下一個Message(鏈式)
這幾個主要的屬性在Handler訊息機制中非常重要,Handler要使用這幾個屬性才能正常運轉。
Handler
Handler有兩個作用:
- 發訊息,子執行緒通過Handler,向訊息佇列發訊息
發訊息有兩種方式,send一個訊息ID(msg.what),或者post一個Runnable(msg.callback),這兩種方式最終都是包裝為一個Message,通過一個sendMessageAtTime函式,把訊息推進佇列裡。 - 處理訊息,Looper通過Handler,逐個處理佇列中的訊息
Looper在逐個處理訊息時,拿到每個msg後,會去執行msg.target.dispatchMessage(msg),這裡面的target其實就是Handler,這裡會做一個判斷,如果msg.callback不為空,說明訊息裡有Runnable(post進來的),就呼叫msg.callback.run,整個過程其實就是在Handler裡呼叫Runnable的run函式;
mHandler.post(new Runnable() {
@Override
public void run() {
}
});
如果msg.callback為空,說明沒有Runnable(send進來的),就呼叫handlemessage,也就是執行Handler的handlemessage函式;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
這樣,Handler訊息機制就能正常運轉了。
Handler訊息機制多見於主執行緒UI重新整理,不過這並不是它的主業,它其實是用來實現Android執行緒間通訊的,所以只要是跨執行緒的通訊,都需要用到Handler,我們可以自己在子執行緒裡寫Looper。
如果我們要在子執行緒裡使用Looper,可以使用HandlerThread,它會幫我們維護一個Looper;如果我們直接用Thread,就需要自己在run函式裡做Looper的prepare和loop。
HanderThread
HanderThread就是handler+thread+looper,它有這麼幾個特點:
1.本質上是一個Thread
2.已經準備好了Looper,可以做Looper迴圈
3.本身是工作執行緒,其looper不在UI主執行緒,可以在handleMessage方法中執行非同步任務
4.雖然不能併發處理多工(因為是一個執行緒,不是執行緒池),但是效能損耗小
5.因為已經有Looper,所以可以線上程裡建立和使用Handler
其他機制
Android的其他非同步處理機制,其實都與Handler機制有關:
- View.post(Runnable)/View.postDelayed(Runnable, long),這個機制一般也是走主執行緒的Handler處理,不過,如果View所在的檢視樹沒有attach到window,就會自己維護一個RunQueue,在檢視樹performTraversals時,把RunQueue裡的訊息全部取出來,讓檢視樹集中處理掉。
- Activity.runOnUiThread(Runnable),這個函式其實是也是走的Handler機制,如果當前執行緒就是UI執行緒,則立即執行;如果當前執行緒不是UI執行緒,就把Runnable發給UI執行緒的訊息佇列,排隊執行。runOnUiThread的原始碼大概是這樣的:
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
- AsyncTask,AsyncTask實際上是個封裝了執行緒池和handler的輕量級非同步框架,它雖然用一個執行緒池做非同步處理,但是處理結果總要提交回主執行緒,實際上就是使用一個Handler(AsyncTask有一個InternalHandler物件)來向主執行緒發訊息(MESSAGE_POST_RESULT),並在主執行緒處理訊息(handleMessage),這就要求把Handler放在主執行緒裡,以便繫結主執行緒的Looper和訊息佇列,所以AsyncTask需要在主執行緒裡建立和呼叫。
有時候,AsyncTask持有的Activity物件可能會被銷燬重建(如螢幕旋轉),這就會導致AsyncTask指向的Activity物件無效,新的Activity無法接收AsyncTask的onPostExecute(),出現結果丟失的現象。
Handler的記憶體洩露
我們使用Handler時,如果用內部類或匿名內部類的方式去使用,就會遇到內部類持有外部物件導致的記憶體洩露(非靜態內部類,在編譯後的建構函式中會引用所在的外部類),解決方式有兩種:
- 使用靜態內部Handler類(+弱引用)。
- 在元件的onDestroy中,呼叫handler.removecallback()方法。
同樣的,由於AsyncTask封裝了handler,也會有同樣的記憶體洩露問題,解決方法也是使用靜態內部類+弱引用,或在onDestroy時及時呼叫asyncTask.cancel()方法,否則就會記憶體洩露,甚至導致崩潰(AsyncTask找不到要處理的View物件)。
更詳細深入的handler通訊機制手寫視訊資料;
1.Handler框架總覽
2.4個關鍵類的一致性問題
3.Android 跨執行緒通訊的深層原理
4.生產者-消費者模式應用
5.ThreadLocal原始碼解析
6.Handler框架手寫實現
7.如何在子執行緒更新UI?
可以加下面的Android技術進階群免費獲取。
附錄;
附錄二;Android進階實戰技術視訊
獲取方式;
加Android進階群;701740775。即可前往免費領取。麻煩備註一下csdn領取資料
相關文章
- Android Handler 訊息機制詳述Android
- Android之Handler訊息傳遞機制詳解Android
- Android訊息機制HandlerAndroid
- android訊息機制—HandlerAndroid
- Android訊息機制Handler用法Android
- Android Handler訊息機制原始碼解讀Android原始碼
- Android的Handler訊息機制 解析Android
- Android 訊息機制詳解(Android P)Android
- Android 訊息機制:Handler、MessageQueue 和 LooperAndroidOOP
- Android Handler MessageQueue Looper 訊息機制原理AndroidOOP
- Android-Handler訊息機制實現原理Android
- Android訊息機制全面解析(Handler,MessageQueue,Looper,Threadlocal)AndroidOOPthread
- Handler訊息機制完全解析Handler解析
- Handler訊息傳遞機制
- Android--Handler機制及原始碼詳解Android原始碼
- android 訊息傳遞機制進階EventBus的深入探究Android
- Android Handler機制之迴圈訊息佇列的退出Android佇列
- Android Handler訊息傳遞機制:圖文解析工作原理Android
- Android全面解析之由淺及深Handler訊息機制Android
- 詳解 Handler 訊息處理機制(附自整理超全 Q&A)
- Android高階進階之路【四】一文讀懂 Handler 機制Android
- iOS進階之訊息轉發機制iOS
- Android Handler機制之訊息池的擴充套件 SimplePool與SynchronizedPoolAndroid套件synchronized
- 學習 Android Handler 訊息機制需要注意這些問題!Android
- 理解 Android 訊息機制Android
- Android 之訊息機制Android
- Android Handler機制之Handler 、MessageQueue 、LooperAndroidOOP
- Handler 訊息機制以及記憶體洩漏記憶體
- Handler訊息處理機制原始碼解析 上原始碼
- Android進階:三、這一次,我們用最詳細的方式解析Android訊息機制的原始碼Android原始碼
- Android非同步訊息機制Android非同步
- Android Handler機制之ThreadLocalAndroidthread
- Android進階(六)Binder機制Android
- 深入理解Android訊息機制Android
- Android高階進階之路【五】深入剖析Android系統Binder通訊機制Android
- Java進階 | Proxy動態代理機制詳解Java
- Android進階知識:Handler相關Android
- Android Handler機制之Message及Message回收機制Android