日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android的消息处理机制——Looper,Handler和Message浅析

發(fā)布時間:2025/3/20 Android 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android的消息处理机制——Looper,Handler和Message浅析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

題外話:

? ? 說來有些慚愧,對于這三者的初步認識居然是在背面試題的時候。那個時候自己接觸Android的時間還不長,學(xué)習(xí)的書籍也就是比較適合入門的《瘋狂Android講義》,當然在學(xué)到Handler這一部分的時候,書中也是有提到一些簡單示例,后來在工作中需要用到這個MessageQueue的時候才開始真正琢磨了一下這三者的聯(lián)系。如果想要對這三者好好理解一番,個人還是比較推薦《深入理解Android卷Ⅰ》。以下對這三者之間的恩怨糾葛的介紹和分析也是參考這本書的相關(guān)章節(jié),算是一篇讀書筆記吧。


概述:

? ? Android的消息傳遞機制是另一種形式的“事件處理”,這種機制主要是為了解決Android應(yīng)用中的多線程問題——Android平臺只允許UI線程修改Activity中的UI組件,這就使得新啟動的線程無法去動態(tài)修改界面組件中的屬性值。但是我們的程序界面不可能是一個靜態(tài)的呈現(xià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中添加消息// 通過Message.obtain()來從消息池中獲得空消息對象,以節(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();}} }

運行效果展示:

?


Log結(jié)果展示:



示例結(jié)果分析:

? ? 大家可以看到我做了連續(xù)兩次的添加消息數(shù)據(jù),在結(jié)果中也有很好的體現(xiàn),不過Looper.prepare();和Handler之間的內(nèi)容卻只執(zhí)行了一次。這是因為我們自定義的線程CustomThread只被start了一次,且start過后一直存在,沒有被銷毀,所以Looper一直存在,MessageQueue一直存在,從而保證了一個Thread只能有一個Looper對象。對于這一點下面會用源碼進行進一步的說明。


機制淺析:

? ? 就應(yīng)用程序而言,Android系統(tǒng)中Java的應(yīng)用程序和其他系統(tǒng)上相同,都是靠消息驅(qū)動來工作的。Android系統(tǒng)中的消息驅(qū)動離不開Looper、Handler和Message這三者,雖說不上哪個更重要一些,不過相對突出的的確是Looper。下面就對這些類逐一地介紹。

Looper類分析:

1.Looper.prepare();

跟蹤prepare()進入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定義:

// sThreadLocal.get() will return null unless you've called prepare(). static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

從以上源碼中我們可以看到,在調(diào)用prepare的線程中,設(shè)置了一個Looper對象,這個Looper對象就保存在這個調(diào)用線程的TLV中。而Looper對象內(nèi)部封裝了一個消息隊列。也就是說prepare通過ThreadLocal機制,把Looper和調(diào)用線程關(guān)聯(lián)在了一起。

2.Looper.loop();

跟蹤loop()進入Android的源碼(此處刪除了一些暫時不太關(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();} }通過上面的分析,Looper有以下幾個作用:

  • 封裝了一個消息隊列.
  • prepare函數(shù)把當前的Looper和調(diào)用prepare的線程(即最終的處理線程)綁定在了一起.
  • 處理線程調(diào)用loop,處理來自該消息隊列中的消息.
當事件源向這個Looper發(fā)送消息的時候,其實就是把消息加到這個Looper的消息列隊里了。那么,該消息就將由和Looper綁定的處理來處理。


Handler類分析:

學(xué)習(xí)Handler之初先來認識一下Handler中所包含的部分成員:

final MessageQueue mQueue; final Looper mLooper; final Callback mCallback;在Handler類中,它的構(gòu)造函數(shù)會把Handler中的消息隊列變量最終都會指向Looper的消息隊列。由于是被指向,那么Handler中的消息隊列其實就是某個Looper的消息隊列。

Looper和Handler的同步關(guān)系說明及HandlerThread的介紹:

? ? Looper和Handler之間其實是存在著同步關(guān)系的。這里對它們之間的同步關(guān)系不做過多介紹,如果想了解可以參看《深入理解Android卷Ⅰ》第128頁。筆者在此只提出一個提醒點:由于HandlerThread完美地解決了Looper和Handler同步過程中可能出現(xiàn)的空指針異常問題,所以在以后的開發(fā)過程中,我們還是多用HandlerThread吧。當然如果不想使用它,那就請使用鎖機制來健壯你的代碼吧,不過這就可能會落下重復(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é)尾,不過對Looper、Handler和Message的認識的確進了一大步。希望看完本文的你也有所收獲。

總結(jié)

以上是生活随笔為你收集整理的Android的消息处理机制——Looper,Handler和Message浅析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。