




版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領
文檔簡介
第Android消息機制Handler深入理解Handler是Android消息機制的上層接口。通過它可以輕松地將一個任務切換到Handler所在的線程中去執行。通常情況下,Handler的使用場景就是更新UI。
Handler的使用
在子線程中,進行耗時操作,執行完操作后,發送消息,通知主線程更新UI。
publicclassActivityextendsandroid.app.Activity{
privateHandlermHandler=newHandler(){
@Override
publicvoidhandleMessage(Messagemsg){
super.handleMessage(msg);
//更新UI
@Override
publicvoidonCreate(BundlesavedInstanceState,PersistableBundlepersistentState){
super.onCreate(savedInstanceState,persistentState);
setContentView(R.layout.activity_main);
newThread(newRunnable(){
@Override
publicvoidrun(){
//執行耗時任務...
//任務執行完后,通知Handler更新UI
Messagemessage=Message.obtain();
message.what=1;
mHandler.sendMessage(message);
).start();
}
Handler架構
Handler消息機制主要包括:MessageQueue、Handler、Looper這三大部分,以及Message。
Message:需要傳遞的消息,可以傳遞數據;
MessageQueue:消息隊列,但是它的內部實現并不是用的隊列,而是通過單鏈表的數據結構來維護消息列表,因為單鏈表在插入和刪除上比較有優勢。主要功能是向消息池投遞消息(MessageQueue.enqueueMessage)和取走消息池的消息(MessageQueue.next)。
Handler:消息輔助類,主要功能是向消息池發送各種消息事件(Handler.sendMessage)和處理相應消息事件(Handler.handleMessage);
Looper:消息控制器,不斷循環執行(Looper.loop),從MessageQueue中讀取消息,按分發機制將消息分發給目標處理者。
從上面的類圖可以看出:
Looper有一個MessageQueue消息隊列;
MessageQueue有一組待處理的Message;
Message中記錄發送和處理消息的Handler;
Handler中有Looper和MessageQueue。
MessageQueue、Handler和Looper三者之間的關系:每個線程中只能存在一個Looper,Looper是保存在ThreadLocal中的。主線程(UI線程)已經創建了一個Looper,所以在主線程中不需要再創建Looper,但是在其他線程中需要創建Looper。每個線程中可以有多個Handler,即一個Looper可以處理來自多個Handler的消息。Looper中維護一個MessageQueue,來維護消息隊列,消息隊列中的Message可以來自不同的Handler。
Handler的運行流程
在子線程執行完耗時操作,當Handler發送消息時,將會調用MessageQueue.enqueueMessage,向消息隊列中添加消息。當通過Looper.loop開啟循環后,會不斷地從消息池中讀取消息,即調用MessageQueue.next,然后調用目標Handler(即發送該消息的Handler)的dispatchMessage方法傳遞消息,然后返回到Handler所在線程,目標Handler收到消息,調用handleMessage方法,接收消息,處理消息。
在子線程創建Handler
classLooperThreadextendsThread{
publicHandlermHandler;
publicvoidrun(){
Looper.prepare();
mHandler=newHandler(){
publicvoidhandleMessage(Messagemsg){
//processincomingmessageshere
Looper.loop();
從上面可以看出,在子線程中創建Handler之前,要調用Looper.prepare()方法,Handler創建后,還要調用Looper.loop()方法。而前面我們在主線程創建Handler卻不要這兩個步驟,因為系統幫我們做了。
主線程的Looper
在ActivityThread的main方法,會調用Looper.prepareMainLooper()來初始化Looper,并調用Looper.loop()方法來開啟循環。
publicfinalclassActivityThreadextendsClientTransactionHandler{
//...
publicstaticvoidmain(String[]args){
//...
Looper.prepareMainLooper();
//...
Looper.loop();
}
Looper
從上可知,要使用Handler,必須先創建一個Looper。
初始化Looper:
publicfinalclassLooper{
publicstaticvoidprepare(){
prepare(true);
privatestaticvoidprepare(BooleanquitAllowed){
if(sThreadLocal.get()!=null){
thrownewRuntimeException(OnlyoneLoopermaybecreatedperthread
sThreadLocal.set(newLooper(quitAllowed));
publicstaticvoidprepareMainLooper(){
prepare(false);
synchronized(Looper.class){
if(sMainLooper!=null){
thrownewIllegalStateException(ThemainLooperhasalreadybeenprepared.
sMainLooper=myLooper();
privateLooper(BooleanquitAllowed){
mQueue=newMessageQueue(quitAllowed);
mThread=Thread.currentThread();
//...
}
從上可以看出,不能重復創建Looper,每個線程只能創建一個。創建Looper,并保存在ThreadLocal。其中ThreadLocal是線程本地存儲區(ThreadLocalStorage,簡稱TLS),每個線程都有自己的私有的本地存儲區域,不同線程之間彼此不能訪問對方的TLS區域。
開啟Looper
publicfinalclassLooper{
//...
publicstaticvoidloop(){
//獲取TLS存儲的Looper對象
finalLooperme=myLooper();
if(me==null){
thrownewRuntimeException(NoLooper;Looper.prepare()wasntcalledonthisthread.
finalMessageQueuequeue=me.mQueue;
//進入loop主循環方法
for(;;){
Messagemsg=queue.next();
//可能會阻塞,因為next()方法可能會無線循環
if(msg==null){
//Nomessageindicatesthatthemessagequeueisquitting.
return;
//Thismustbeinalocalvariable,incaseaUIeventsetsthelogger
finalPrinterlogging=me.mLogging;
if(logging!=null){
logging.println(Dispatchingto+msg.target++
msg.callback+:+msg.what);
//...
finallongdispatchStart=needStartTimeSystemClock.uptimeMillis():0;
finallongdispatchEnd;
try{
//獲取msg的目標Handler,然后分發Message
msg.target.dispatchMessage(msg);
dispatchEnd=needEndTimeSystemClock.uptimeMillis():0;
finally{
if(traceTag!=0){
Trace.traceEnd(traceTag);
//...
msg.recycleUnchecked();
}
Handler
創建Handler:
publicclassHandler{
//...
publicHandler(){
this(null,false);
publicHandler(Callbackcallback,Booleanasync){
//...
//必須先執行Looper.prepare(),才能獲取Looper對象,否則為null
mLooper=Looper.myLooper();
if(mLooper==null){
thrownewRuntimeException(
Cantcreatehandlerinsidethread+Thread.currentThread()
+thathasnotcalledLooper.prepare()
mQueue=mLooper.mQueue;
//消息隊列,來自Looper對象
mCallback=callback;
//回調方法
mAsynchronous=async;
//設置消息是否為異步處理方式
}
發送消息:
子線程通過Handler的post()方法或send()方法發送消息,最終都是調用sendMessageAtTime()方法。
post方法:
publicfinalBooleanpost(Runnabler){
returnsendMessageDelayed(getPostMessage(r),0);
publicfinalBooleanpostAtTime(Runnabler,longuptimeMillis){
returnsendMessageAtTime(getPostMessage(r),uptimeMillis);
publicfinalBooleanpostAtTime(Runnabler,Objecttoken,longuptimeMillis){
returnsendMessageAtTime(getPostMessage(r,token),uptimeMillis);
publicfinalBooleanpostDelayed(Runnabler,longdelayMillis){
returnsendMessageDelayed(getPostMessage(r),delayMillis);
privatestaticMessagegetPostMessage(Runnabler){
Messagem=Message.obtain();
m.callback=r;
returnm;
}
send方法:
publicfinalBooleansendMessage(Messagemsg){
returnsendMessageDelayed(msg,0);
publicfinalBooleansendEmptyMessage(intwhat){
returnsendEmptyMessageDelayed(what,0);
publicfinalBooleansendEmptyMessageDelayed(intwhat,longdelayMillis){
Messagemsg=Message.obtain();
msg.what=what;
returnsendMessageDelayed(msg,delayMillis);
publicfinalBooleansendEmptyMessageAtTime(intwhat,longuptimeMillis){
Messagemsg=Message.obtain();
msg.what=what;
returnsendMessageAtTime(msg,uptimeMillis);
publicfinalBooleansendMessageDelayed(Messagemsg,longdelayMillis){
if(delayMillis0){
delayMillis=0;
returnsendMessageAtTime(msg,SystemClock.uptimeMillis()+delayMillis);
sendMessageAtTime()
publicBooleansendMessageAtTime(Messagemsg,longuptimeMillis){
MessageQueuequeue=mQueue;
if(queue==null){
RuntimeExceptione=newRuntimeException(
this+sendMessageAtTime()calledwithnomQueue
Log.w(Looper,e.getMessage(),e);
returnfalse;
returnenqueueMessage(queue,msg,uptimeMillis);
privateBooleanenqueueMessage(MessageQ
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
- 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
- 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
- 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 工地宰羊過節活動方案
- 少年向上活動方案
- 小小特種兵訓練活動方案
- 展播心得征集活動方案
- 小微企業信貸活動方案
- 希望小屋走訪活動方案
- 工會作品征集活動方案
- 巧手搭建活動方案
- 小班教育活動方案
- 市場特價活動方案
- 武繼祥-矯形器的臨床應用
- 云南省昆明市盤龍區2024年八年級下學期期末數學試卷附答案
- 2022-2023學年河南省鄭州市高一下學期期末考試數學試題(解析版)
- 2023初三一模閔行英語卷+答案
- 園區零碳園區建設方案
- +畢業試卷(試題)-2023-2024學年六年級下冊數學蘇教版
- 工程管理之施工資料管理培訓
- 變壓器油箱焊接工藝
- 國學療愈行業分析
- 小學低年級自主識字的教學策略
- (2023)義務教育新課程標準生物(2022年版)必考試題含答案
評論
0/150
提交評論