android子線程發消息給主線程
❶ Android 中的「子線程」解析
Android 中線程可分為 主線程 和 子線程 兩類,其中主線程也就是 UI線程 ,它的主要這作用就是運行四大組件、處理界面交互。子線程則主要是處理耗時任務,也是我們要重點分析的。
首先 Java 中的各種線程在 Android 里是通用的,Android 特有的線程形態也是基於 Java 的實現的,所以有必要先簡單的了解下 Java 中的線程,本文主要包括以下內容:
在 Java 中要創建子線程可以直接繼承 Thread 類,重寫 run() 方法:
或者實現 Runnable 介面,然後用Thread執行Runnable,這種方式比較常用:
簡單的總結下:
Callable 和 Runnable 類似,都可以用來處理具體的耗時任務邏輯的,但是但具體的差別在哪裡呢?看一個小例子:
定義 MyCallable 實現了 Callable 介面,和之前 Runnable 的 run() 方法對比下, call() 方法是有返回值的哦,泛型就是返回值的類型:
一般會通過線程池來執行 Callable (線程池相關內容後邊會講到),執行結果就是一個 Future 對象:
可以看到,通過線程池執行 MyCallable 對象返回了一個 Future 對象,取出執行結果。
Future 是一個介面,從其內部的方法可以看出它提供了取消任務(有坑!!!)、判斷任務是否完成、獲取任務結果的功能:
Future 介面有一個 FutureTask 實現類,同時 FutureTask 也實現了 Runnable 介面,並提供了兩個構造函數:
用 FutureTask 一個參數的構造函數來改造下上邊的例子:
FutureTask 內部有一個 done() 方法,代表 Callable 中的任務已經結束,可以用來獲取執行結果:
所以 Future + Callable 的組合可以更方便的獲取子線程任務的執行結果,更好的控制任務的執行,主要的用法先說這么多了,其實 AsyncTask 內部也是類似的實現!
注意, Future 並不能取消掉運行中的任務,這點在後邊的 AsyncTask 解析中有提到。
Java 中線程池的具體的實現類是 ThreadPoolExecutor ,繼承了 Executor 介面,這些線程池在 Android 中也是通用的。使用線程池的好處:
常用的構造函數如下:
一個常規線程池可以按照如下方式來實現:
執行任務:
基於 ThreadPoolExecutor ,系統擴展了幾類具有新特性的線程池:
線程池可以通過 execute() 、 submit() 方法開始執行任務,主要差別從方法的聲明就可以看出,由於 submit() 有返回值,可以方便得到任務的執行結果:
要關閉線程池可以使用如下方法:
IntentService 是 Android 中一種特殊的 Service,可用於執行後台耗時任務,任務結束時會自動停止,由於屬於系統的四大組件之一,相比一般線程具有較高的優先順序,不容易被殺死。用法和普通 Service 基本一致,只需要在 onHandleIntent() 中處理耗時任務即可:
至於 HandlerThread,它是 IntentService 內部實現的重要部分,細節內容會在 IntentService 源碼中說到。
IntentService 首次創建被啟動的時候其生命周期方法 onCreate() 會先被調用,所以我們從這個方法開始分析:
這里出現了 HandlerThread 和 ServiceHandler 兩個類,先搞明白它們的作用,以便後續的分析。
首先看 HandlerThread 的核心實現:
首先它繼承了 Thread 類,可以當做子線程來使用,並在 run() 方法中創建了一個消息循環系統、開啟消息循環。
ServiceHandler 是 IntentService 的內部類,繼承了 Handler,具體內容後續分析:
現在回過頭來看 onCreate() 方法主要是一些初始化的操作, 首先創建了一個 thread 對象,並啟動線程,然後用其內部的 Looper 對象 創建一個 mServiceHandler 對象,將子線程的 Looper 和 ServiceHandler 建立了綁定關系,這樣就可以使用 mServiceHandler 將消息發送到子線程去處理了。
生命周期方法 onStartCommand() 方法會在 IntentService 每次被啟動時調用,一般會這里處理啟動 IntentService 傳遞 Intent 解析攜帶的數據:
又調用了 start() 方法:
就是用 mServiceHandler 發送了一條包含 startId 和 intent 的消息,消息的發送還是在主線程進行的,接下來消息的接收、處理就是在子線程進行的:
當接收到消息時,通過 onHandleIntent() 方法在子線程處理 intent 對象, onHandleIntent() 方法執行結束後,通過 stopSelf(msg.arg1) 等待所有消息處理完畢後終止服務。
為什麼消息的處理是在子線程呢?這里涉及到 Handler 的內部消息機制,簡單的說,因為 ServiceHandler 使用的 Looper 對象就是在 HandlerThread 這個子線程類里創建的,並通過 Looper.loop() 開啟消息循環,不斷從消息隊列(單鏈表)中取出消息,並執行,截取 loop() 的部分源碼:
dispatchMessage() 方法間接會調用 handleMessage() 方法,所以最終 onHandleIntent() 就在子線程中劃線執行了,即 HandlerThread 的 run() 方法。
這就是 IntentService 實現的核心,通過 HandlerThread + Hanlder 把啟動 IntentService 的 Intent 從主線程切換到子線程,實現讓 Service 可以處理耗時任務的功能!
AsyncTask 是 Android 中輕量級的非同步任務抽象類,它的內部主要由線程池以及 Handler 實現,在線程池中執行耗時任務並把結果通過 Handler 機制中轉到主線程以實現UI操作。典型的用法如下:
從 Android3.0 開始,AsyncTask 默認是串列執行的:
如果需要並行執行可以這么做:
AsyncTask 的源碼不多,還是比較容易理解的。根據上邊的用法,可以從 execute() 方法開始我們的分析:
看到 @MainThread 註解了嗎?所以 execute() 方法需要在主線程執行哦!
進而又調用了 executeOnExecutor() :
可以看到,當任務正在執行或者已經完成,如果又被執行會拋出異常!回調方法 onPreExecute() 最先被執行了。
傳入的 sDefaultExecutor 參數,是一個自定義的串列線程池對象,所有任務在該線程池中排隊執行:
可以看到 SerialExecutor 線程池僅用於任務的排隊, THREAD_POOL_EXECUTOR 線程池才是用於執行真正的任務,就是我們線程池部分講到的 ThreadPoolExecutor :
再回到 executeOnExecutor() 方法中,那麼 exec.execute(mFuture) 就是觸發線程池開始執行任務的操作了。
那 executeOnExecutor() 方法中的 mWorker 是什麼? mFuture 是什麼?答案在 AsyncTask 的構造函數中:
原來 mWorker 是一個 Callable 對象, mFuture 是一個 FutureTask 對象,繼承了 Runnable 介面。所以 mWorker 的 call() 方法會在 mFuture 的 run() 方法中執行,所以 mWorker 的 call() 方法在線程池得到執行!
同時 doInBackground() 方法就在 call() 中方法,所以我們自定義的耗時任務邏輯得到執行,不就是我們第二部分講的那一套嗎!
doInBackground() 的返回值會傳遞給 postResult() 方法:
就是通過 Handler 將最終的耗時任務結果從子線程發送到主線程,具體的過程是這樣的, getHandler() 得到的就是 AsyncTask 構造函數中初始化的 mHandler , mHander 又是通過 getMainHandler() 賦值的:
可以在看到 sHandler 是一個 InternalHandler 類對象:
所以 getHandler() 就是在得到在主線程創建的 InternalHandler 對象,所以
就可以完成耗時任務結果從子線程到主線程的切換,進而可以進行相關UI操作了。
當消息是 MESSAGE_POST_RESULT 時,代表任務執行完成, finish() 方法被調用:
如果任務沒有被取消的話執行 onPostExecute() ,否則執行 onCancelled() 。
如果消息是 MESSAGE_POST_PROGRESS , onProgressUpdate() 方法被執行,根據之前的用法可以 onProgressUpdate() 的執行需要我們手動調用 publishProgress() 方法,就是通過 Handler 來發送進度數據:
進行中的任務如何取消呢?AsyncTask 提供了一個 cancel(boolean mayInterruptIfRunning) ,參數代表是否中斷正在執行的線程任務,但是呢並不靠譜, cancel() 的方法注釋中有這么一段:
大致意思就是調用 cancel() 方法後, onCancelled(Object) 回調方法會在 doInBackground() 之後被執行而 onPostExecute() 將不會被執行,同時你應該 doInBackground() 回調方法中通過 isCancelled() 來檢查任務是否已取消,進而去終止任務的執行!
所以只能自己動手了:
AsyncTask 整體的實現流程就這些了,源碼是最好的老師,自己跟著源碼走一遍有些問題可能就豁然開朗了!
❷ Android——消息分發機制
什麼是 Handler 機制 ?
Handler 機制是 Android 中用於 線程間通信 的一套通信機制。
為什麼是 Handler ?Handler 機制為什麼被那麼多次的提及 ?
從Android4.0開始,Android 中網路請求強制不允許在主線程中操作,而更新UI的操作則不允許在子線程中執行。當在子線程中執行網路請求,拿到伺服器返回的數據之後,要更新UI。由於系統的要求,勢必會產生一種矛盾:數據在子線程,更新UI要在主線程。此時我們必須要把數據返回到主線程中才行,Handler機制應運而生。
Android 中針對耗時的操作,放在主線程操作,輕者會造成 UI 卡頓,重則會直接無響應,造成 Force Close。同時在 Android 3.0 以後,禁止在主線程進行網路請求。
針對耗時或者網路操作,那就不能在主線程進行直接操作了,需要放在子線程或者是工作線程中進行操作,操作完成以後,再更新主線程即 UI 線程。這里就涉及到一個問題了,在子線程執行完成以後,怎麼能更新到主線程即 UI 線程呢,針對以上問題,就需要用到 Android 的消息機制了,即: Handler, Message, MessageQueue, Looper 全家桶
Handler機制中最重要的四個對象
Handler的構造方法:
Looper :
Handler的使用:
MessageQueue:
Looper.loop()
Handler.dispatchMessage()
handler導致activity內存泄露的原因:
handler發送的消息在當前handler的消息隊列中,如果此時activity finish掉了,那麼消息隊列的消息依舊會由handler進行處理,若此時handler聲明為內部類(非靜態內部類),我們知道內部類天然持有外部類的實例引用,這樣在GC垃圾回收機制進行回收時發現這個Activity居然還有其他引用存在,因而就不會去回收這個Activity,進而導致activity泄露。
假如在子線程執行了耗時操作,這時用戶操作進入了其他的 acitvity, 那麼 MainActivity 就會被內存回收的,但是這個時候發現 Handler 還在引用著 MainActivity,內存無法及時回收,造成內存泄漏。
Handler 防止內存泄漏常見方法:
為什麼通過 Handler 可以把子線程的結果通知或者攜帶給 UI 線程 ?
這里的 Handler 指的是主線程的 Handler ,同時與 Handler 配套的 Looper , MessageQueue 是在 UI 線程初始化的,所以在子線程中調用 Handler 發送消息可以更新 UI 線程。
Looper 在 UI 線程源碼, 在 ActivityThread 類:
❸ [Android源碼分析] - 非同步通信Handler機制
一、問題:在Android啟動後會在新進程里創建一個主線程,也叫UI線程( 非線程安全 )這個線程主要負責監聽屏幕點擊事件與界面繪制。當Application需要進行耗時操作如網路請求等,如直接在主線程進行容易發生ANR錯誤。所以會創建子線程來執行耗時任務,當子線程執行完畢需要通知UI線程並修改界面時,不可以直接在子線程修改UI,怎麼辦?
解決方法:Message Queue機制可以實現子線程與UI線程的通信。
該機制包括Handler、Message Queue、Looper。Handler可以把消息/ Runnable對象 發給Looper,由它把消息放入所屬線程的消息隊列中,然後Looper又會自動把消息隊列里的消息/Runnable對象 廣播 到所屬線程里的Handler,由Handler處理接收到的消息或Runnable對象。
1、Handler
每次創建Handler對象時,它會自動綁定到創建它的線程上。如果是主線程則默認包含一個Message Queue,否則需要自己創建一個消息隊列來存儲。
Handler是多個線程通信的信使。比如在線程A中創建AHandler,給它綁定一個ALooper,同時創建屬於A的消息隊列AMessageQueue。然後在線程B中使用AHandler發送消息給ALooper,ALooper會把消息存入到AMessageQueue,然後再把AMessageQueue廣播給A線程里的AHandler,它接收到消息會進行處理。從而實現通信。
2、Message Queue
在主線程里默認包含了一個消息隊列不需要手動創建。在子線程里,使用Looper.prepare()方法後,會先檢查子線程是否已有一個looper對象,如果有則無法創建,因為每個線程只能擁有一個消息隊列。沒有的話就為子線程創建一個消息隊列。
Handler類包含Looper指針和MessageQueue指針,而Looper里包含實際MessageQueue與當前線程指針。
下面分別就UI線程和worker線程講解handler創建過程:
首先,創建handler時,會自動檢查當前線程是否包含looper對象,如果包含,則將handler內的消息隊列指向looper內部的消息隊列,否則,拋出異常請求執行looper.prepare()方法。
- 在 UI線程 中,系統自動創建了Looper 對象,所以,直接new一個handler即可使用該機制;
- 在 worker線程 中,如果直接創建handler會拋出運行時異常-即通過查『線程-value』映射表發現當前線程無looper對象。所以需要先調用Looper.prepare()方法。在prepare方法里,利用ThreadLocal<Looper>對象為當前線程創建一個Looper(利用了一個Values類,即一個Map映射表,專為thread存儲value,此處為當前thread存儲一個looper對象)。然後繼續創建handler, 讓handler內部的消息隊列指向該looper的消息隊列(這個很重要,讓handler指向looper里的消息隊列,即二者共享同一個消息隊列,然後handler向這個消息隊列發送消息,looper從這個消息隊列獲取消息) 。然後looper循環消息隊列即可。當獲取到message消息,會找出message對象里的target,即原始發送handler,從而回調handler的handleMessage() 方法進行處理。
- handler與looper共享消息隊列 ,所以handler發送消息只要入列,looper直接取消息即可。
- 線程與looper映射表 :一個線程最多可以映射一個looper對象。通過查表可知當前線程是否包含looper,如果已經包含則不再創建新looper。
5、基於這樣的機制是怎樣實現線程隔離的,即在線程中通信呢。
核心在於 每一個線程擁有自己的handler、message queue、looper體系 。而 每個線程的Handler是公開 的。B線程可以調用A線程的handler發送消息到A的共享消息隊列去,然後A的looper會自動從共享消息隊列取出消息進行處理。反之一樣。
二、上面是基於子線程中利用主線程提供的Handler發送消息出去,然後主線程的Looper從消息隊列中獲取並處理。那麼還有另外兩種情況:
1、主線程發送消息到子線程中;
採用的方法和前面類似。要在子線程中實例化AHandler並設定處理消息的方法,同時由於子線程沒有消息隊列和Looper的輪詢,所以要加上Looper.prepare(),Looper.loop()分別創建消息隊列和開啟輪詢。然後在主線程中使用該AHandler去發送消息即可。
2、子線程A與子線程B之間的通信。
1、 Handler為什麼能夠實現不同線程的通信?核心點在哪?
不同線程之間,每個線程擁有自己的Handler、消息隊列和Looper。Handler是公共的,線程可以通過使用目標線程的Handler對象來發送消息,這個消息會自動發送到所屬線程的消息隊列中去,線程自帶的Looper對象會不斷循環從裡面取出消息並把消息發送給Handler,回調自身Handler的handlerMessage方法,從而實現了消息的線程間傳遞。
2、 Handler的核心是一種事件激活式(類似傳遞一個中斷)的還是主要是用於傳遞大量數據的?重點在Message的內容,偏向於數據傳輸還是事件傳輸。
目前的理解,它所依賴的是消息隊列,發送的自然是消息,即類似事件中斷。
0、 Android消息處理機制(Handler、Looper、MessageQueue與Message)
1、 Handler、Looper源碼閱讀
2、 Android非同步消息處理機制完全解析,帶你從源碼的角度徹底理解
謝謝!
wingjay

❹ 在Android開發中怎麼把子線程中的數據傳輸到主線中(大神求詳細過程
這個谷歌早已經給你實現了,使用handler:
例如在主線程創建handler
子線程發消息到這個handler
Handler handler=new Handler(){
@Override
public boolean handleMessage(Message msg){
switch (msg.what){
case 1:
//TODO
break;
}
}
//子線程里
Message msg = new Message();
msg.what = 1;
msg.object=XX;//傳對象,還有arg1、arg2……
handler.sendMessage(msg);
❺ 深入分析Android-Handler消息機制
Handler是Android消息機制的上層介面。通過它可以輕松地將一個任務切換到Handler所在的線程中去執行。通常情況下,Handler的使用場景就是 更新UI 。
在子線程中,進行耗時操作,執行完操作後,發送消息,通知主線程更新UI。
Handler消息機制主要包括: MessageQueue 、 Handler 、 Looper 這三大部分,以及 Message 。
從上面的類圖可以看出:
MessageQueue、Handler和Looper三者之間的關系: 每個線程中只能存在一個Looper,Looper是保存在ThreadLocal中的。 主線程(UI線程)已經創建了一個Looper,所以在主線程中不需要再創建Looper,但是在其他線程中需要創建Looper。 每個線程中可以有多個Handler,即一個Looper可以處理來自多個Handler的消息。 Looper中維護一個MessageQueue,來維護消息隊列,消息隊列中的Message可以來自不同的Handler。
在子線程執行完耗時操作,當Handler發送消息時,將會調用 MessageQueue.enqueueMessage ,向消息隊列中添加消息。 當通過 Looper.loop 開啟循環後,會不斷地從消息池中讀取消息,即調用 MessageQueue.next , 然後調用目標Handler(即發送該消息的Handler)的 dispatchMessage 方法傳遞消息, 然後返回到Handler所在線程,目標Handler收到消息,調用 handleMessage 方法,接收消息,處理消息。
從上面可以看出,在子線程中創建Handler之前,要調用 Looper.prepare() 方法,Handler創建後,還要調用 Looper.loop() 方法。而前面我們在主線程創建Handler卻不要這兩個步驟,因為系統幫我們做了。
初始化Looper :
從上可以看出,不能重復創建Looper,每個線程只能創建一個。創建Looper,並保存在 ThreadLocal 。其中ThreadLocal是線程本地存儲區(Thread Local Storage,簡稱TLS),每個線程都有自己的私有的本地存儲區域,不同線程之間彼此不能訪問對方的TLS區域。
開啟Looper
創建Handler :
發送消息 :
post方法:
send方法:
❻ Android進程間和線程間通信方式
進程:是具有一定獨立功能的程序關於某個數據集合上的一次運行活動,進程是系統進行資源分配和調度的一個獨立單位。
線程:是進程的一個實體,是CPU調度和分派的基本單位,它是比進程更小的能獨立運行的基本單位。線程自己基本上不擁有系統資源,只擁有一些在運行中必不可少的資源(如程序計數器,一組寄存器和棧),但是它可與同屬一個進程的其他的線程共享進程所擁有的全部資源。
區別:
(1)、一個程序至少有一個進程,一個進程至少有一個線程;
(2)、線程的劃分尺度小於進程,使得多線程程序的並發性高;
(3)、進程在執行過程中擁有獨立的內存單元,而多個線程共享內存,但線程之間沒有單獨的地址空間,一個線程死掉就等於整個進程死掉。
---------------------
一、Android進程間通信方式
1.Bundle
由於Activity,Service,Receiver都是可以通過Intent來攜帶Bundle傳輸數據的,所以我們可以在一個進程中通過Intent將攜帶數據的Bundle發送到另一個進程的組件。
缺點:無法傳輸Bundle不支持的數據類型。
2.ContentProvider
ContentProvider是Android四大組件之一,以表格的方式來儲存數據,提供給外界,即Content Provider可以跨進程訪問其他應用程序中的數據。用法是繼承ContentProvider,實現onCreate,query,update,insert,delete和getType方法,onCreate是負責創建時做一些初始化的工作,增刪查改的方法就是對數據的查詢和修改,getType是返回一個String,表示Uri請求的類型。注冊完後就可以使用ContentResolver去請求指定的Uri。
3.文件
兩個進程可以到同一個文件去交換數據,我們不僅可以保存文本文件,還可以將對象持久化到文件,從另一個文件恢復。要注意的是,當並發讀/寫時可能會出現並發的問題。
4.Broadcast
Broadcast可以向android系統中所有應用程序發送廣播,而需要跨進程通訊的應用程序可以監聽這些廣播。
5.AIDL方式
Service和Content Provider類似,也可以訪問其他應用程序中的數據,Content Provider返回的是Cursor對象,而Service返回的是Java對象,這種可以跨進程通訊的服務叫AIDL服務。
AIDL通過定義服務端暴露的介面,以提供給客戶端來調用,AIDL使伺服器可以並行處理,而Messenger封裝了AIDL之後只能串列運行,所以Messenger一般用作消息傳遞。
6.Messenger
Messenger是基於AIDL實現的,服務端(被動方)提供一個Service來處理客戶端(主動方)連接,維護一個Handler來創建Messenger,在onBind時返回Messenger的binder。
雙方用Messenger來發送數據,用Handler來處理數據。Messenger處理數據依靠Handler,所以是串列的,也就是說,Handler接到多個message時,就要排隊依次處理。
7.Socket
Socket方法是通過網路來進行數據交換,注意的是要在子線程請求,不然會堵塞主線程。客戶端和服務端建立連接之後即可不斷傳輸數據,比較適合實時的數據傳輸
二、Android線程間通信方式
一般說線程間通信主要是指主線程(也叫UI線程)和子線程之間的通信,主要有以下兩種方式:
1.AsyncTask機制
AsyncTask,非同步任務,也就是說在UI線程運行的時候,可以在後台的執行一些非同步的操作;AsyncTask可以很容易且正確地使用UI線程,AsyncTask允許進行後台操作,並在不顯示使用工作線程或Handler機制的情況下,將結果反饋給UI線程。但是AsyncTask只能用於短時間的操作(最多幾秒就應該結束的操作),如果需要長時間運行在後台,就不適合使用AsyncTask了,只能去使用Java提供的其他API來實現。
2.Handler機制
Handler,繼承自Object類,用來發送和處理Message對象或Runnable對象;Handler在創建時會與當前所在的線程的Looper對象相關聯(如果當前線程的Looper為空或不存在,則會拋出異常,此時需要在線程中主動調用Looper.prepare()來創建一個Looper對象)。使用Handler的主要作用就是在後面的過程中發送和處理Message對象和讓其他的線程完成某一個動作(如在工作線程中通過Handler對象發送一個Message對象,讓UI線程進行UI的更新,然後UI線程就會在MessageQueue中得到這個Message對象(取出Message對象是由其相關聯的Looper對象完成的),並作出相應的響應)。
三、Android兩個子線程之間通信
面試的過程中,有些面試官可能會問Android子線程之間的通信方式,由於絕大部分程序員主要關注的是Android主線程和子線程之間的通信,所以這個問題很容易讓人懵逼。
主線程和子線程之間的通信可以通過主線程中的handler把子線程中的message發給主線程中的looper,或者,主線程中的handler通過post向looper中發送一個runnable。但looper默認存在於main線程中,子線程中沒有Looper,該怎麼辦呢?其實原理很簡單,把looper綁定到子線程中,並且創建一個handler。在另一個線程中通過這個handler發送消息,就可以實現子線程之間的通信了。
子線程創建handler的兩種方式:
方式一:給子線程創建Looper對象:
new Thread(new Runnable() {
public void run() {
Looper.prepare(); // 給這個Thread創建Looper對象,一個Thead只有一個Looper對象
Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
Looper.loop(); // 不斷遍歷MessageQueue中是否有消息
};
}).start();
---------------------
方式二:獲取主線程的looper,或者說是UI線程的looper:
new Thread(new Runnable() {
public void run() {
Handler handler = new Handler(Looper.getMainLooper()){ // 區別在這!!!
@Override
public void handleMessage(Message msg) {
Toast.makeText(getApplicationContext(), "handleMessage", Toast.LENGTH_LONG).show();
}
};
handler.sendEmptyMessage(1);
};
}).start();
---------------------
❼ Android在子線程用handler發送的消息,主線程是怎麼loop到的
因為你是在主線程創建的handler實例,比如你是這樣實例化handler
然後調用looper.loop();就開始了消息循環。這就是為什麼在主線程發消息住線程還能收到消息的原因。因為發送消息的實例是在主線程實例化的就有了主線程的looper。
❽ Android如何將數據從子線程中傳到主線程
這個谷歌早已經給你實現了,使用handler:
例如在主線程創建handler
子線程發消息到這個handler
Handler handler=new Handler(){
@Override
public boolean handleMessage(Message msg){
switch (msg.what){
case 1:
//TODO
break;
}
}
//子線程里
Message msg = new Message();
msg.what = 1;
msg.object=XX;//傳對象,還有arg1、arg2……
handler.sendMessage(msg);
❾ Android在子線程用handler發送的消息,主線程是怎麼loop到的
,Handler,Looper,MessageQueue這三者如何關聯的?這里拿最簡單的new 一個無參Handler為例。在創建無參的Handler時會對其中變數MessageQueue賦值,這個值就是Looper對象的MessageQueue,那麼這個Looper對象又是在那創建的呢?如果是在app進程中的話,在啟動該app時會調用ActivityThread,main方法進入主線程,在main函數中會有初始化Looper,並調用looper.loop()輪詢MessageQueue中的Message,這個Message是handler在調用sendMessage或者post時會將Message enqueue到MessageQueue中,這樣Looper 就會loop 到Handler發送到MessageQueue中的Message,loop時就會dispatchMessage了,再然後就是Hanlder處理message了,在調用sendMessage時,handler必須要重寫handleMessage方法。這樣就完成了發送消息和處理消息。在app的進程中,thread1還是發送消息到主線程中的MessageQueue,這個MessageQueue在首次啟動app時就在創建Looper時已經創建好了。那麼如果不是在app進程怎麼辦呢?假如是在ActivityManagerService中使用Handler的話呢?ActivityManagerService可以理解為在system_server進程中的一個線程,在啟動system_server時並沒有像啟動一個app進程那樣系統已經創建好了Looper,那麼我們如果要使用Handler機制,就必須要有Handler,Looper,MessageQueue,Message,一來我們可以自己手動調用Looper.prepare和Looper.loop,另外,系統也已經封裝好了,就是HandlerThread。HandlerThread是一個Thread,在裡面已經將Looper,MessageQueue准備好了,這時候創建Handler時,將HandlerThread的Looper傳給Handler就行了,這樣Handler,Looper,MessageQueue就都有了,就可以利用Handler機制進行線程間通信了。
❿ Android在子線程用handler發送的消息,主線程是怎麼loop到的
因為你是在主線程創建的handler實例,比如你是這樣實例化handler
那麼我們進到handler源碼看一下
可以看到這里會調用重載的另外一個構造方法,我們再跟進
我們可以看到
mLooper=looper.myLooper();
這是獲取當前線程的looper實例,也就是主線程的looper。所以當發送消息的時候主線程就可以獲取到消息。往下看系統還會mLooper是否為空,如果為空就會拋出異常,意思是當前線程沒有looper實例,這也是我們在子線程中沒有創建looper的實例的時候創建handler會報錯的原因,主線程不會報錯是因為程序在啟動的時候在activitythread中的main方法就創建了looper實例,看系統源碼
然後調用looper.loop();就開始了消息循環。這就是為什麼在主線程發消息住線程還能收到消息的原因。因為發送消息的實例是在主線程實例化的就有了主線程的looper。