androidhandler子線程
㈠ Android的handler機制的原理
Android的handler機制的原理分為非同步通信准備,消息發送,消息循環,消息處理。
1、非同步通信准備
在主線程中創建處理器對象(Looper)、消息隊列對象(Message Queue)和Handler對象。
2、消息入隊
工作線程通過Handler發送消息(Message) 到消息隊列(Message Queue)中。
3、消息循環
消息出隊: Looper循環取出消息隊列(Message Queue) 中的的消息(Message)。
消息分發: Looper將取出的消息 (Message) 發送給創建該消息的處理者(Handler)。
4、消息處理
處理者(Handler) 接收處理器(Looper) 發送過來的消息(Message),根據消息(Message) 進行U操作。
handler的作用
handler是android線程之間的消息機制,主要的作用是將一個任務切換到指定的線程中去執行,(准確的說是切換到構成handler的looper所在的線程中去出處理)android系統中的一個例子就是主線程中的所有操作都是通過主線程中的handler去處理的。
Handler的運行需要底層的 messagequeue和 looper做支撐。
㈡ [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
![](https://avatars0.githubusercontent.com/u/9619875?v=3&s=460)
㈢ Android面試 Handler機制
Handler就是解決線程與線程間的通信。
當我們在子線程處理耗時操作,耗時操作完成後我們需要更新UI的時候,這就是需要使用Handler來處理了,因為子線程不能更 新UI,Handler能讓我們容易的把任務切換回來它所在的線程。
消息處理機制本質:一個線程開啟循環模式持續監聽並依次處理其他線程給它發的消息。
一個線程可以有多個Handler,通過new Handler的方式創建。
一個線程只能有一個Looper,通過Looper.perpare方法會創建一個Looper保存在ThreadLocal中,每個線程都有一個LocalThreadMap,會將Looper保存在對應線程中的LocalThreadMap,key為ThreadLocal,value為Looper。
內部類持有外部類的對象,handler持有activity的對象,當頁面activity關閉時,handler還在發送消息,handler持有activity的對象,導致handler不能及時被回收,所以造成內存泄漏。
因為當handler發送消息時,會有耗時操作,並且會利用線程中的looper和messageQueue進行消息發送,looper和messageQueue的生命周期是很長的,和application一樣,所以handler不容易被銷毀,所以造成內存泄漏。
解決方案有:
可以在子線程中創建Handler,我們需要調用Looper.perpare和Looper.loop方法。或者通過獲取主線程的looper來創建Handler。
應該調用Looper的quit方法,因為可以將looper中的messageQueue里的message都移除掉,並且將內存釋放。
通過synchronized鎖機制保證線程安全。
Message.obtain來創建Message。這樣會復用之前的Message的內存,不會頻繁的創建對象,導致內存抖動。
點擊按鈕的時候會發送消息到Handler,但是為了保證優先執行,會加一個標記非同步,同時會發送一個target為null的消息,這樣在使用消息隊列的next獲取消息的時候,如果發現消息的target為null,那麼會遍歷消息隊列將有非同步標記的消息獲取出來優先執行,執行完之後會將target為null的消息移除。(同步屏障)
更多內容戳這里(整理好的各種文集)
㈣ 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創建子線程
創建後台線程的方法有多種,這里說三種,可以回去試試
1、使用Android系統工具類 AsyncTask(Params,Progress,Result)
AsyncTask是一個輕量級線程,三個泛型參數分別是 Params傳入參數,int型Progress為進度條進度,Result為返回值
要使用AsyncTask,必須繼承之並復寫其中的幾個重要的函數。
onPreExecute(), 該方法將在執行實際的後台操作前被UI thread調用。可以在該方法中做一些准備工作,如在界面上顯示一個進度條。
doInBackground(Params...), 將在onPreExecute 方法執行後馬上執行,該方法運行在後台線程中。這里將主要負責執行那些很耗時的後台計算工作。可以調用 publishProgress方法來更新實時的任務進度。該方法是抽象方法,子類必須實現。
onProgressUpdate(Progress...),在publishProgress方法被調用後,UI thread將調用這個方法從而在界面上展示任務的進展情況,例如通過一個進度條進行展示。
onPostExecute(Result), 在doInBackground 執行完成後,onPostExecute 方法將被UI thread調用,後台的計算結果將通過該方法傳遞到UI thread.
註:Task必須在UI線程中創建,並調用並且只能調用一次execute方法,該方法的參數為傳入的泛型Params。
其餘函數最好不要手動調用,容易造成線程崩潰。多次調用Task,容易造成線程池溢出。
2、使用Handler和HandlerThread
誤區: Handler handler = new Handler ();
handler.post(r);
這種做法看似創建了一個線程,但實際上handler只是直接調用Runnable中的run() 方法,而不執行線程的start()函數,所以這兩句代碼執行後,程序仍然在UI線程中執行。所以我們引入HandlerThread,因為HandlerThread中有一個Looper對象,用以循環消息隊列。
為了使用Looper,必須子類化Handler,並復寫它的構造函數。
class MyHandler extends Handler{
public MyHandler() {}
public MyHandler(Looper looper){
super (looper);
}
public void handleMessage(Message msg){
//....這里運行耗時的過程
}
}
}
handleMessage(Message msg)函數用以接收消息,msg則是從UI線程中發出的消息,可以傳遞各種對象,根據這些對象和數值進行操作。
有了Handler子類,則可以在UI線程中進行創建和初始化
HandlerThread handlerThread = new HandlerThread( "backgroundThread" );
handlerThread.start();
MyHandler myHandler = new MyHandler(handlerThread.getLooper());
Message msg = myHandler.obtainMessage();
//....此處對msg進行賦值,可以創建一個Bundle進行承載
msg.sendToTarget();
之後如果需要調用線程,只要對handler傳入msg,就可以執行相應的過程了
最後,很重要的一點,HandlerThread 不隨Activity的生命周期結束而消亡,所以必須復寫Ondestory(),調用HandlerThread .stop()
3、使用線程同步 synchronized、 wait()、 notify()
使用線程同步機制synchronized實現多線程操作,相對來說比較復雜,但也是靈活性最佳、效率最高的一種做法,在產品開發當中也使用得最廣。本人水平相當有限,也只學得一點皮毛。
synchronized相當於一把鎖,當線程運行的時候,會同時有幾個線程訪問一個對象,對其進行操作或者修改。這可能引起很不良的後果(例如改變判定條件,或者在別的線程還沒使用完的時候對象已經被析構等等),所以必須對一些對象進行加鎖,保證它在同一時間只允許被一個線程訪問。
synchronized使用方法有兩種:
<1> 同步方法在方法名前加入synchronized關鍵字,則該方法在同一時間內只允許一個線程訪問它,其代碼邏輯較為簡單,但使用起來不太靈活,並且大大降低效率,耗時太長的同步方法甚至會使得多線程失去原本的意義成為單線程
<2>同步參數 對某一個代碼塊加鎖,並且以synchronized(obj)的方式,表明該代碼塊內的obj對象是線程同步的。這個做法使得代碼靈活性大大加強,縮小同步代碼塊的范圍,並且可以在不同的函數體和類內進行同步,唯一遺憾的是實現起來比較復雜,容易產生一些問題
而wait()和notify(),必須在synchronized鎖的代碼塊內執行,否則系統將會報錯。
有了以上基礎,就可以很容易的創建後台線程了
Private Runnable backgroundRunnable = new Runnable () {
@Override
public void run() {
if(isFinish){
//.....
break;
}
for(;;){
synchronized(this){
//....寫耗時過程
wait();
}
}
}
}
UI線程中,就是一般的創建線程過程了
Thread backgroundThread = new Thread (backgroundRunnable);
backgroundThread.start();
這樣,在後台線程中會不斷的循環,當執行完一次過程以後就會wait()休眠。然後在OnTouchListener或者OnClickListener內相應的位置執行
synchronized(backgroundRunnable){
backgroundRunnable.notify();
}
當用戶觸摸屏幕產生一個event的時候,線程就會被喚醒,執行下一次循環。
最後,還是內存安全問題,必須復寫Activity中的OnDestory()方法,將標志量isFinish設為false,並且backgroundThread .stop()
㈥ 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是在主線程中嗎
Handler對拍頌歷象一般是在主線程中創建的,在子線程中執行耗時操櫻凳作發送消息,推襲搜薦你看這篇博客http://www.cnblogs.com/codingmyworld/archive/2011/09/12/2174255.html 講解很清晰
㈧ 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,Messag,另外,系統也已經封裝好了,就是HandlerThread。HandlerThread是一個Thread,在裡面已經將Looper,MessageQueue准備好了,這時候創建Handler時,將HandlerThread的Looper傳給Handler就行了,這樣Handler,Looper,MessageQueue就都有了,就可以利用Handler機制進行線程間通信了。
㈨ Android 為什麼使用Handler
在Android的UI開發中,我們經常會使用Handler來控制主UI程序的界面變化。有關Handler的作用,我們總結為:與其他線程協同工作,接收其他線程的消息並通過接收到的消息更或穗拆新主UI線程的內容。
我們假設在一個UI界面上面,有一個按鈕,當點擊這個按鈕的時候,會進行網路連接,並把網路上的一個字元串拿下來顯示到界面上的一個 TextView上面,這時就出現了一個問題,如果這個網路連接的延遲過大,可能是10秒鍾甚至更長,那我們的界面將處於一直假死狀態,而如果這段時間超 過5秒鍾的話,程序會出現異常。
這時我們會想到使用線程來完成以上工作,即當按鈕被按下的時候新開啟一個線程來完成網路連接工作,並把得到的結果更新到UI上面。但是,這時候又會 出現另一個問題,在Android中,主線程是非線程安全的,也就是說UI的族讓更新只能在本線程中完成,其他線程無法直接對主線程進行操作。
為了解決以上問題,Android設計了Handler機制,由Handler來負責與子線程進行通訊,從而讓子線程與主線程之間建立起協作的橋梁,使Android的UI更新的問題得到完美的解決。接下來舉例來詮釋Handler的基本使用方法。
Handler的工作原理
一般情況下,在主線程中我們綁定了Handler,並在事件觸發上面創建新的衫棗線程用於完成某些耗時的操作,當子線程中的工作完成之後,會對Handler發送一個完成的信號,而Handler接收到信號後,就進行主UI界面的更新操作。
2
Handler與子線程協作實例
1、創建Handler實現類,在主UI所在類中的內部類
class MyHandler extends Handler {
public MyHandler() { }
public MyHandler(Looper L) {
super(L);
}
// 重寫handleMessage方法,接受數據並更新UI
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
//此處根據msg內容進行UI操作
}
}
2、子線程的實現
class MyThread implements Runnable {
public void run() {
Message msg = new Message();
Bundle b = new Bundle();
b.putString("cmd", "update");
msg.setData(b);
MainActivity.this.myHandler.sendMessage(msg);
//通知Handler更新UI
}
}
通過以上的兩個實現,我們只需要在MainActivity中聲明MyHandler實例對象就可以完成線程之間的通訊和界面的更新操作。
MyHandler myHandler = newMyHandler();
㈩ Android-Handle(線程間通信)詳解
線程間通信是在Android開發中比較經常遇到的,我們刷新UI界面一般是通過子線程做完某些事情後,要改變主頁面就要通過數據的通信,讓主線程接收到信息後自己改變UI界面。
1. Handle 先進先出原則;
2. Looper 類用來管理特定線程內對象之間的消息交換(MessageExchange);
3. Message 類用來保存數據。
1.Looper: 一個線程可以產生一個Looper對象,由它來管理此線程里的MessageQueue(消息隊列);
2.Handler: 你可以構造Handler對象來與Looper溝通,以便push新消息到MessageQueue里;或者接收Looper從Message Queue取出)所送來的消息;
android.os.Message的主要功能是進行消息的封裝,同時可以指定消息的操作形式,Message類定義的變數和常用方法如下:
在整個消息處理機制中,message又叫task,封裝了任務攜帶的信息和處理該任務的handler。message的用法比較簡單,但是有這么幾點需要注意:
在使用Handler處理Message時,需要Looper(通道)來完成。在一個Activity中,系統會自動幫用戶啟動Looper對象,而在一個用戶自定義的類中,則需要用戶手工調用Looper類中的方法,然後才可以正常啟動Looper對象。Looper的字面意思是「循環者」,它被設計用來使一個普通線程變成Looper線程。所謂Looper線程就是循環工作的線程。在程序開發中(尤其是GUI開發中),我們經常會需要一個線程不斷循環,一旦有新任務則執行,執行完繼續等待下一個任務,這就是Looper線程。使用Looper類創建Looper線程很簡單:
這是在子線程中創建Handler的情況,如果在主線程中創建Handler是不需要調用 Looper.prepare(); 和 Looper.loop(); 方法。
Handler是更新UI界面的機制,也是消息處理的機制。我們可以通過Handle發送消息,也可以處理消息。
Android在設計的時候,封裝了一套消息創建、傳遞、處理機制,如果不遵循這樣的機制就沒有辦法更新UI信息,就會拋出異常。
創建Handler實例化對象時,可以重寫的回調方法: