Android异步处理:Handler+Looper+MessageQueue深入详解
為什么80%的碼農(nóng)都做不了架構(gòu)師?>>>
轉(zhuǎn)載自:http://blog.csdn.net/mylzc/article/details/6771331,在原文基礎(chǔ)上修改整理再發(fā)布。
概述:Android使用消息機(jī)制實(shí)現(xiàn)線程間的通信,線程通過(guò)Looper建立自己的消息循環(huán),MessageQueue是FIFO的消息隊(duì)列,Looper負(fù)責(zé)從MessageQueue中取出消息,并且分發(fā)到消息指定目標(biāo)Handler對(duì)象。Handler對(duì)象綁定到線程的局部變量Looper,封裝了發(fā)送消息和處理消息的接口。
例子:在介紹原理之前,我們先介紹Android線程通訊的一個(gè)例子,這個(gè)例子實(shí)現(xiàn)點(diǎn)擊按鈕之后從主線程發(fā)送消息"hello"到另外一個(gè)名為” CustomThread”的線程。
Log打印結(jié)果:
原理:
我們看到,為一個(gè)線程建立消息循環(huán)有四個(gè)步驟:
1、? 初始化Looper
2、? 綁定handler到CustomThread實(shí)例的Looper對(duì)象
3、? 定義處理消息的方法
4、? 啟動(dòng)消息循環(huán)
下面我們以這個(gè)例子為線索,深入Android源代碼,說(shuō)明Android Framework是如何建立消息循環(huán),并對(duì)消息進(jìn)行分發(fā)的。
1、? 初始化Looper : Looper.prepare()
Looper.java
private static final ThreadLocal sThreadLocal = new ThreadLocal(); public static final void prepare() {if (sThreadLocal.get() != null) {throw new RuntimeException("Only one Looper may be created per thread");}sThreadLocal.set(new Looper()); }
一個(gè)線程在調(diào)用Looper的靜態(tài)方法prepare()時(shí),這個(gè)線程會(huì)新建一個(gè)Looper對(duì)象,并放入到線程的局部變量中,而這個(gè)變量是不和其他線程共享的(關(guān)于ThreadLocal的介紹)。下面我們看看Looper()這個(gè)構(gòu)造函數(shù):
Looper.java
final MessageQueue mQueue; private Looper() {mQueue = new MessageQueue();mRun = true;mThread = Thread.currentThread();}
可以看到在Looper的構(gòu)造函數(shù)中,創(chuàng)建了一個(gè)消息隊(duì)列對(duì)象mQueue,此時(shí),調(diào)用Looper. prepare()的線程就建立起一個(gè)消息循環(huán)的對(duì)象(此時(shí)還沒(méi)開(kāi)始進(jìn)行消息循環(huán))。
2、? 綁定handler到CustomThread實(shí)例的Looper對(duì)象 : mHandler= new Handler()
Handler.java
final MessageQueue mQueue;final Looper mLooper; public Handler() {if (FIND_POTENTIAL_LEAKS) {final Class<? extends Handler> klass = getClass();if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&(klass.getModifiers() & Modifier.STATIC) == 0) {Log.w(TAG, "The following Handler class should be static or leaks might occur: " +klass.getCanonicalName());}}mLooper = Looper.myLooper();if (mLooper == null) {throw new RuntimeException("Can't create handler inside thread that has not called Looper.prepare()");}mQueue = mLooper.mQueue;mCallback = null; }
Handler通過(guò)mLooper = Looper.myLooper();綁定到線程的局部變量Looper上去,同時(shí)Handler通過(guò)mQueue =mLooper.mQueue;獲得線程的消息隊(duì)列。此時(shí),Handler就綁定到創(chuàng)建此Handler對(duì)象的線程的消息隊(duì)列上了。
3、定義處理消息的方法:Override public void handleMessage (Message msg){}? ? ?子類需要覆蓋這個(gè)方法,實(shí)現(xiàn)接受到消息后的處理方法。
4、啟動(dòng)消息循環(huán) : Looper.loop()
? ? ? 所有準(zhǔn)備工作都準(zhǔn)備好了,是時(shí)候啟動(dòng)消息循環(huán)了!Looper的靜態(tài)方法loop()實(shí)現(xiàn)了消息循環(huán)。
Looper.java
public static final void loop() {Looper me = myLooper();MessageQueue queue = me.mQueue;// Make sure the identity of this thread is that of the local process,// and keep track of what that identity token actually is.Binder.clearCallingIdentity();final long ident = Binder.clearCallingIdentity();while (true) {Message msg = queue.next(); // might block//if (!me.mRun) {// break;//}if (msg != null) {if (msg.target == null) {// No target is a magic identifier for the quit message.return;}if (me.mLogging!= null) me.mLogging.println(">>>>> Dispatching to " + msg.target + " "+ msg.callback + ": " + msg.what);msg.target.dispatchMessage(msg);if (me.mLogging!= null) me.mLogging.println("<<<<< Finished to " + msg.target + " "+ msg.callback);// Make sure that during the course of dispatching the// identity of the thread wasn't corrupted.final long newIdent = Binder.clearCallingIdentity();if (ident != newIdent) {Log.wtf("Looper", "Thread identity changed from 0x"+ Long.toHexString(ident) + " to 0x"+ Long.toHexString(newIdent) + " while dispatching to "+ msg.target.getClass().getName() + " "+ msg.callback + " what=" + msg.what);}msg.recycle();}}}
while(true)體現(xiàn)了消息循環(huán)中的“循環(huán)“,Looper會(huì)在循環(huán)體中調(diào)用queue.next()獲取消息隊(duì)列中需要處理的下一條消息。當(dāng)msg != null且msg.target != null時(shí),調(diào)用msg.target.dispatchMessage(msg);分發(fā)消息,當(dāng)分發(fā)完成后,調(diào)用msg.recycle();回收消息。
msg.target是一個(gè)handler對(duì)象,表示需要處理這個(gè)消息的handler對(duì)象。Handler的void dispatchMessage(Message msg)方法如下:
Handler.java
public void dispatchMessage(Message msg) {if (msg.callback != null) {handleCallback(msg);} else {if (mCallback != null) {if (mCallback.handleMessage(msg)) {return;}}handleMessage(msg);} }
可見(jiàn),當(dāng)msg.callback== null 并且mCallback == null時(shí),這個(gè)例子是由handleMessage(msg);處理消息,上面我們說(shuō)到子類覆蓋這個(gè)方法可以實(shí)現(xiàn)消息的具體處理過(guò)程。
總結(jié):從上面的分析過(guò)程可知,消息循環(huán)的核心是Looper,Looper持有消息隊(duì)列MessageQueue對(duì)象,一個(gè)線程可以把Looper設(shè)為該線程的局部變量,這就相當(dāng)于這個(gè)線程建立了一個(gè)對(duì)應(yīng)的消息隊(duì)列。Handler的作用就是封裝發(fā)送消息和處理消息的過(guò)程,讓其他線程只需要操作Handler就可以發(fā)消息給創(chuàng)建Handler的線程。由此可以知道,在上一篇《 Android異步處理一:使用Thread+Handler實(shí)現(xiàn)非UI線程更新UI界面》中,UI線程在創(chuàng)建的時(shí)候就建立了消息循環(huán)(在ActivityThread的public static final void main(String[] args)方法中實(shí)現(xiàn)),因此我們可以在其他線程給UI線程的handler發(fā)送消息,達(dá)到更新UI的目的。完整代碼:
package com.xsjayz.looper;import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button;public class LooperThreadActivity extends Activity {private final int MSG_HELLO = 0;private Handler handler;private Button button;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);button = (Button) findViewById(R.id.send_btn);new CustomThread().start();// 點(diǎn)擊按鈕時(shí)發(fā)送消息button.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {String str = "hello";Log.d("Test", "MainThread is ready to send msg0000000000:"+ str);// 發(fā)送消息到CustomThread實(shí)例handler.obtainMessage(MSG_HELLO, str).sendToTarget();}});}/*** 建立消息循環(huán)的步驟*/class CustomThread extends Thread {@Overridepublic void run() {// 1、初始化LooperLooper.prepare();// 2、綁定handler到CustomThread實(shí)例的Looper對(duì)象handler = new Handler() {// 3、定義處理消息的方法public void handleMessage(Message msg) {switch (msg.what) {case MSG_HELLO:Log.d("Test", "CustomThread receive msg1111111111:"+ (String) msg.obj);}}};// 4、啟動(dòng)消息循環(huán)Looper.loop();}} }布局文件:main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:orientation="vertical" ><TextViewandroid:layout_width="fill_parent"android:layout_height="wrap_content"android:text="@string/hello" /><Buttonandroid:id="@+id/send_btn"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@string/send_msg" ></Button></LinearLayout>
轉(zhuǎn)載于:https://my.oschina.net/xsjayz/blog/76313
總結(jié)
以上是生活随笔為你收集整理的Android异步处理:Handler+Looper+MessageQueue深入详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 美国虚拟主机大打安全牌争抢国内高端外贸主
- 下一篇: Liferay 控制面板在指定文件夹添加