转自: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
當初信紙內容的交辦事項。

更多相关文章

  1. [Android] 任意时刻从子线程切换到主线程的实现原理及加强版
  2. -----------关于android屏幕保护---屏幕常亮---------屏幕解锁--
  3. Android 分析Native库的加载过程及x86系统运行arm库的原理
  4. flex 4.5 开发android 的文章
  5. Android热修复原理(一)热修复框架对比和代码修复
  6. android watchdog原理
  7. Android 动画实现原理

随机推荐

  1. android 自定义对话框 背景透明
  2. Android之checkbox使用
  3. android 获取进程名字
  4. android菜鸟
  5. android使用Intent操作拨打电话和发送短
  6. Android怎么从设置相册中的照片作背景(刚
  7. android中读取短信
  8. 第五节cocos2dx的jni部分
  9. Android(安卓)实现Activity后台运行
  10. android spinner 每行字体颜色都变化