[Android]android.os 源代码中的Looper,Handler,Message,MessageQueue
转自:http://milochen.wordpress.com/2011/03/25/understanding-android-os-src-looperhandler-message-messagequeue/
作者:Milochen
HiAll:
Handler,Message,Looper,MessageQueue是android.os中的class
也是深度開發Application時,必須具備的基本觀念,若清楚了解,
便可運用的當。
因為網路有太多模糊不清的文章,大家說法看起來也都不太一樣,
很容易讓人猜東猜西,想東想西的。至於,不想瞎猜的話,就不如直接把sourcecode都讀懂吧。
因此本篇文章,目地在於,快速引導大家快速「正確」的了解,重點在於「正確性」
並且透過靜態tracecode的方式,跟大家解釋它sourcecode的運作原理。
因此,對於四個class沒信心的時候,
就直接將文章看下去,文章會完整交代tracesourcecode的部份。
關於這四個class的結論:
========================================================
整個Handler,Message,MessageQueue,Looper它們四個class只有一個共同的目標
就是讓程式碼,可以丟到其它thread去執行。這麼作有什麼好處呢??
例如android的GUI元件是threadsafe的(意思是,元件的使用,無法multi-thread執行)
Activity的畫面顯示是由UIThread所負責的,若是你寫了mutlti-thread程式時
又想更新畫面,就必須要將Thread內部的一段程式碼,交由UIThread來執行才行。
OK,上面四個class的共同目地已經說明完畢了,那麼這四個class有其分工方式。
因此每個class的設計又有不同目地。說明如下…
Handler的目地,在於提供callbackfunction,預其給其它Thread作執行
但Handler又要如何transfer至其它Thread呢?於是有了Message
Message的目地,將Handler包裝起來,傳送給其它Thread
但是同時有多條thread不斷的在系統中傳遞Message那麼如何緩衝呢?
MessageQueue的目地,是為了讓Message能夠作緩衝,好讓Message先暫存起來。
因此,當Message已經被放在其它Thread上的MessageQueue之後,
它裡面包著Handler,而Handler上的callbackfunction總得有人來執行吧??
Looper的目地:
就是為了將Message由Thread所對應的MessageQueue取出來,並且拿出Handler
來執行它上面的callbackfunction.
當Looper.java中的loop()被呼叫起來之後,它就是在反覆作這件事
不斷將Handler由Message拆包出來,並且執行Handler上的callbackfunction。
======================================================================
以上,已經將這四個class的關係完整說明了。看到這邊您還有疑慮嗎 ?
接下來小弟就直接講tracesource的部份,
教你快速 trace 懂這些 code,迅速驗證出這四個 class 的用途。
以下開始 trace source code .. Follow Me ^____^
Looper中的mThread,mQueue只有在Ctor建立,並且”不會再更改”
mThread=Thread.currentThread()//紀綠此Looper由那條Thread建立
mQueue=newMessageQueue()//每個Looper只有唯一的Queue
主要的執行函式為
Looper.java:loop(){
MessageQueuequeue=myLooper().mQueue//取得CurrentThread下Looper的MsgQueue
while(true){
Messagemsg=queue.next()//跳到msg一個message
msg.target.dispatchMessage(msg)
//target被almost設定的方式,是透過Message.obtain(Handlerh)設h為target
msg.recycle();//InMessageclass,只有recycle()與obtain()作sync同步
}
}
上面程式中,所提到的東西,在以下深入探討。
(1)dispatchMessage(msg)是如何重要呢?
它呼叫Handler上的handleMessage().
———————————————
PS:一般來說,我們會寫個EHandlerextendsHandler,
並且重寫handleMessage()function好讓Handler上的handlerMessage()
被UIThread呼叫,來更新畫面。
——————————
(2)至於loop()是如何被使用的呢?
typicalexample大約是這樣子的
classLooperThreadextendsThread{
publicHandlermHandler;
publicvoidrun(){
Looper.prepare();
mHandler=newHandler(){
publicvoidhandleMessage(Messagemsg){
//processincomingmessageshere
}
};
Looper.loop();
}
類似的typicalexample在Android系統中的ActivityThread.java::main()
publicstaticfinalvoidmain(String[]args){
Looper.prepareMainLooper();
ActivityThreadthread=newActivityThread();
Looper.loop();
}
額外話…
此範例trace下去將發現,Looper.mMainLooper變數被設定為
(Looper)sThreadLocal.get()
許多重要的androidsourcecode皆會透過getMainLooper()函數取出
Looper.mMainLooper
(3)msg.target是個Handler類別,又是從何而來的呢?
直接copy高煥堂網路文章中的examplecode過來…
講義摘錄之28:Anrdroid的MessageQueue(3/3)的examplecode如下
classAnyClassimplementsRunnable{
publicvoidrun(){
Looper.prepare();
h=newHandler(){
publicvoidhandleMessage(Messagemsg){
EventHandlerha=newEventHandler(Looper.getMainLooper());
Stringobj=(String)msg.obj+”,myThread”;
Messagem=ha.obtainMessage(1,1,1,obj);
ha.sendMessage(m);//sendMessage的原理,請見(4)的說明
}
};
Looper.loop();
}
}
我們直接由此來作解釋,
追蹤當中的obtainMssage可發現target的由來。原理如下
Handler.java:MessageobtainMessage(intwhat,intarg1,intarg2)
Message.java:
staticMessageobtain(Handlerh,intwhat,intarg1,intarg2){
Messagem=obtain();
m.target=h;//這邊就是msg.target的由來
m.what=what;
m.arg1=arg1;
m.arg2=arg2;
}
而Messagem=obtain()是執行下面這段程式
publicstaticMessageobtain(){
synchronized(mPoolSync){//與recycle()共用mPoolSync
if(mPool!=null){
Messagem=mPool;
mPool=m.next;
m.next=null;
returnm;
}
}
returnnewMessage();
}
因此你可從samplecode知道
Handler呼叫obtainMessage的時候,其實是由mPool取出Message來
將msg.target設為原Handler.並且設定好what,arg1,arg2等參數
好讓Looper來執行它…
———————————————–
(4)接續(3)中的examplecode,它的sendMessage()又作了什麼事呢?
classAnyClassimplementsRunnable{
publicvoidrun(){
Looper.prepare();
h=newHandler(){
publicvoidhandleMessage(Messagemsg){
EventHandlerha=newEventHandler(Looper.getMainLooper());
Stringobj=(String)msg.obj+”,myThread”;
Messagem=ha.obtainMessage(1,1,1,obj);
ha.sendMessage(m);//sendMessage作什麼事呢?
}
};
Looper.loop();
}
}
以這個例子,簡單來說,Looper.getMainLooper()會回傳一個ActivityThread的
Looperobject,即為Looper.mMainLooper.而mMainLooper有自己的mQueue
==================================================
在此穿插一小段 sendMessage() 的作用
Handler本身在暫存一個mQueue, 當Handler的成員函數sendMessage被呼叫時,即是把帶著Handlerha的Messagem,enqueue至Handler自己存存的mQueue中。而mQueue的設置,通常是在建構子就被決定好的。因此你得特別注意 Handler 的建構子。
==================================================
像上面的例子中 sendMessage 即是把帶著 Handler ha 的 Message m,enqueue 至 mMainLooper.mQueue
sendMessage即是把帶著Handlerha的Messagem,enqueue至mMainLooper.mQueue
好讓mMainLooper.loop()函數把m由這個mMainLooper.mQueue取出(取出時名為msg)
來dispatchMessage,因此就會執行到msg.target.handleMessage(0
也就是exmaplecode中的ha.handleMessage();
因為在Handlerha=newHandler(Looperlooper)這Ctor時,
ha.mLooper=looper便被紀錄下來,而且ha.mQueue=looper.mQueue也被紀錄下來
也就是looper.mQueue(PS:若是用newHandler(),則looper取Looper.myLooper())
當ha.sendMessage被執行時,便將msg塞入looper.mQueue
—————————————————————–
(5)所以整個Looper,Message,MessageQueue,Handler的運作原理是什麼?
因此你的ha=JohnHandler(MaryLooper)就像信紙一樣,上面寫著DearMaryLooper:
上面寫著要執行的程式碼handleMessage(msg)
透過信封(Message),以Handler.java的sendMessage將信紙(Handler)傳出去
傳到MaryLooper的個人信箱MessageQueue(也就是MaryLooper.mQueue)
在MaryLooper中,有個有個固定的loop()會不斷被執行
(假設當初宣告此looper的thread,有去running此functionloop的話)
那麼loop會收到Messagemsg.而msg.target(Handler)即為JohnHandler這封信紙
看著JohnHandler上有handleMessage()的信紙內容,
故對Handler執行了dipsatchMessage(),因此執行了JohnHandler
當初信紙內容的交辦事項。
更多相关文章
- [Android] 任意时刻从子线程切换到主线程的实现原理及加强版
- -----------关于android屏幕保护---屏幕常亮---------屏幕解锁--
- Android 分析Native库的加载过程及x86系统运行arm库的原理
- flex 4.5 开发android 的文章
- Android热修复原理(一)热修复框架对比和代码修复
- android watchdog原理
- Android 动画实现原理