Android的消息处理机制——Looper,Handler和Message浅析
題外話:
? ? 說(shuō)來(lái)有些慚愧,對(duì)于這三者的初步認(rèn)識(shí)居然是在背面試題的時(shí)候。那個(gè)時(shí)候自己接觸Android的時(shí)間還不長(zhǎng),學(xué)習(xí)的書(shū)籍也就是比較適合入門(mén)的《瘋狂Android講義》,當(dāng)然在學(xué)到Handler這一部分的時(shí)候,書(shū)中也是有提到一些簡(jiǎn)單示例,后來(lái)在工作中需要用到這個(gè)MessageQueue的時(shí)候才開(kāi)始真正琢磨了一下這三者的聯(lián)系。如果想要對(duì)這三者好好理解一番,個(gè)人還是比較推薦《深入理解Android卷Ⅰ》。以下對(duì)這三者之間的恩怨糾葛的介紹和分析也是參考這本書(shū)的相關(guān)章節(jié),算是一篇讀書(shū)筆記吧。
概述:
? ? Android的消息傳遞機(jī)制是另一種形式的“事件處理”,這種機(jī)制主要是為了解決Android應(yīng)用中的多線程問(wèn)題——Android平臺(tái)只允許UI線程修改Activity中的UI組件,這就使得新啟動(dòng)的線程無(wú)法去動(dòng)態(tài)修改界面組件中的屬性值。但是我們的程序界面不可能是一個(gè)靜態(tài)的呈現(xiàn),所以這就必須用到本博客中提到的三個(gè)大類(lèi)了。
簡(jiǎn)單示例:
代碼展示:
public class LooperThreadActivity extends Activity {private final int MSG_HELLO = 0;private Handler mHandler;private CustomThread mThread = null;private static final String TAG = LooperThreadActivity.class.getSimpleName();@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);mThread = new CustomThread();mThread.start();Button sendButton = (Button) findViewById(R.id.send_button);final EditText contentEditText = (EditText) findViewById(R.id.content_edittext);sendButton.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {String msgText = contentEditText.getText().toString();sendMessage(msgText);}});}private void sendMessage(String content) {Toast.makeText(this, "send msg: " + content, 0).show();// TODO 1.向MessageQueue中添加消息// 通過(guò)Message.obtain()來(lái)從消息池中獲得空消息對(duì)象,以節(jié)省資源Log.i(TAG, "------------> send msg 1.");Message msg = mHandler.obtainMessage(MSG_HELLO, content);msg.sendToTarget();Log.i(TAG, "------------> send msg 2.");Message msg2 = mHandler.obtainMessage(MSG_HELLO, content + "2");msg2.sendToTarget();}class CustomThread extends Thread {@Overridepublic void run() {Looper.prepare();Log.i(TAG, "------------> loop.pre.");mHandler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case MSG_HELLO:Log.i(TAG, "------------> receive msg.");Toast.makeText(LooperThreadActivity.this, "receive msg: " + (String) msg.obj, 0).show();}}};Looper.loop();}} }
運(yùn)行效果展示:
?
Log結(jié)果展示:
示例結(jié)果分析:
? ? 大家可以看到我做了連續(xù)兩次的添加消息數(shù)據(jù),在結(jié)果中也有很好的體現(xiàn),不過(guò)Looper.prepare();和Handler之間的內(nèi)容卻只執(zhí)行了一次。這是因?yàn)槲覀冏远x的線程CustomThread只被start了一次,且start過(guò)后一直存在,沒(méi)有被銷(xiāo)毀,所以Looper一直存在,MessageQueue一直存在,從而保證了一個(gè)Thread只能有一個(gè)Looper對(duì)象。對(duì)于這一點(diǎn)下面會(huì)用源碼進(jìn)行進(jìn)一步的說(shuō)明。
機(jī)制淺析:
? ? 就應(yīng)用程序而言,Android系統(tǒng)中Java的應(yīng)用程序和其他系統(tǒng)上相同,都是靠消息驅(qū)動(dòng)來(lái)工作的。Android系統(tǒng)中的消息驅(qū)動(dòng)離不開(kāi)Looper、Handler和Message這三者,雖說(shuō)不上哪個(gè)更重要一些,不過(guò)相對(duì)突出的的確是Looper。下面就對(duì)這些類(lèi)逐一地介紹。
Looper類(lèi)分析:
1.Looper.prepare();
跟蹤prepare()進(jìn)入Android的源碼,我們可以發(fā)現(xiàn)以下源代碼:
private static void prepare(boolean quitAllowed) {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper(quitAllowed));}
sThreadLocal定義:
從以上源碼中我們可以看到,在調(diào)用prepare的線程中,設(shè)置了一個(gè)Looper對(duì)象,這個(gè)Looper對(duì)象就保存在這個(gè)調(diào)用線程的TLV中。而Looper對(duì)象內(nèi)部封裝了一個(gè)消息隊(duì)列。也就是說(shuō)prepare通過(guò)ThreadLocal機(jī)制,把Looper和調(diào)用線程關(guān)聯(lián)在了一起。
2.Looper.loop();
跟蹤loop()進(jìn)入Android的源碼(此處刪除了一些暫時(shí)不太關(guān)聯(lián)的代碼):
public static void loop() {final Looper me = myLooper();if (me == null) {throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");}final MessageQueue queue = me.mQueue;Binder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();for (;;) {Message msg = queue.next(); // might blockif (msg == null) {// No message indicates that the message queue is quitting.return;}msg.target.dispatchMessage(msg);msg.recycle();} }通過(guò)上面的分析,Looper有以下幾個(gè)作用:
- 封裝了一個(gè)消息隊(duì)列.
- prepare函數(shù)把當(dāng)前的Looper和調(diào)用prepare的線程(即最終的處理線程)綁定在了一起.
- 處理線程調(diào)用loop,處理來(lái)自該消息隊(duì)列中的消息.
Handler類(lèi)分析:
學(xué)習(xí)Handler之初先來(lái)認(rèn)識(shí)一下Handler中所包含的部分成員:
final MessageQueue mQueue; final Looper mLooper; final Callback mCallback;在Handler類(lèi)中,它的構(gòu)造函數(shù)會(huì)把Handler中的消息隊(duì)列變量最終都會(huì)指向Looper的消息隊(duì)列。由于是被指向,那么Handler中的消息隊(duì)列其實(shí)就是某個(gè)Looper的消息隊(duì)列。
Looper和Handler的同步關(guān)系說(shuō)明及HandlerThread的介紹:
? ? Looper和Handler之間其實(shí)是存在著同步關(guān)系的。這里對(duì)它們之間的同步關(guān)系不做過(guò)多介紹,如果想了解可以參看《深入理解Android卷Ⅰ》第128頁(yè)。筆者在此只提出一個(gè)提醒點(diǎn):由于HandlerThread完美地解決了Looper和Handler同步過(guò)程中可能出現(xiàn)的空指針異常問(wèn)題,所以在以后的開(kāi)發(fā)過(guò)程中,我們還是多用HandlerThread吧。當(dāng)然如果不想使用它,那就請(qǐng)使用鎖機(jī)制來(lái)健壯你的代碼吧,不過(guò)這就可能會(huì)落下重復(fù)造輪子的口舌了。
參考資料:
1.《瘋狂Android講義》
2.《深入理解Android卷Ⅰ》
3.網(wǎng)絡(luò)資源:http://www.cnblogs.com/codingmyworld/archive/2011/09/14/2174255.html
4.網(wǎng)絡(luò)資源:http://www.cnblogs.com/bastard/archive/2012/06/08/2541944.html
5.網(wǎng)絡(luò)資源:http://blog.csdn.net/mylzc/article/details/6771331
尾聲:
雖然已經(jīng)“稀里糊涂”到了結(jié)尾,不過(guò)對(duì)Looper、Handler和Message的認(rèn)識(shí)的確進(jìn)了一大步。希望看完本文的你也有所收獲。
總結(jié)
以上是生活随笔為你收集整理的Android的消息处理机制——Looper,Handler和Message浅析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android简单手势滑动的识别
- 下一篇: Android UI编程之自定义控件初步