Android消息處理有三大核心類:Looper, Handler和Message,下面就是詳細的诠釋這三者作用與關聯。
Looper
Looper時常被稱為消息泵,它是被設計用來使一個普通線程程式設計Looper線程,所謂的Looper線程就是循環工作的線程。這樣的線程會不斷循環,一旦有新任務則執行,執行完之後繼續等待下一個任務。使用Looper類建立Looper線程隻有兩行核心代碼:
public class LooperThread extends Thread {
@Override
public void run() {
// 将目前線程初始化為Looper線程
Looper.prepare();
// ...其他處理,如執行個體化handler
// 開始循環處理消息隊列
Looper.loop();
}
}
這樣就把該LooperThread線程轉化為Looper線程了。
1. Looper.prepare()
圖1 普通線程轉化為Looper線程
通過Looper類将一個普通線程轉化為Looper線程,則在該Looper線程中,有一個Looper對象,它的内部維護了一個消息隊列MessageQueue。其中,一個線程中至多隻能有一個Looper對象,這一點在源碼中可以看出:
public class Looper {
// 每個線程中的Looper對象其實是一個ThreadLocal,即線程本地存儲(TLS)對象
private static final ThreadLocal sThreadLocal = new ThreadLocal();
// Looper内的消息隊列
final MessageQueue mQueue;
// 目前線程
Thread mThread;
// 。。。其他屬性
// 每個Looper對象中有它的消息隊列,和它所屬的線程
private Looper() {
mQueue = new MessageQueue();
mRun = true;
mThread = Thread.currentThread();
}
// 我們調用該方法會在調用線程的TLS中建立Looper對象
public static final void prepare() {
if (sThreadLocal.get() != null) {
// 試圖在有Looper的線程中再次建立Looper将抛出異常
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper());
}
// 其他方法
}
關于Looper的構造函數:
(1)建立并維護一個MessageQueue 的消息隊列;
(2)将Looper對象指向它的執行個體所線上程(即Looper在建立的時候會關聯一個線程);
關于Looper.prepare()函數:
**(1)**ThreadLocal對象用于儲存Looper對象的引用,其本身是一個
public static final void loop() {
Looper me = myLooper(); //得到目前線程Looper
MessageQueue queue = me.mQueue; //得到目前looper的MQ
// 這兩行沒看懂= = 不過不影響了解
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// 開始循環
while (true) {
Message msg = queue.next(); // 取出message
if (msg != null) {
if (msg.target == null) {
// message沒有target為結束信号,退出循環
return;
}
// 日志。。。
if (me.mLogging!= null) me.mLogging.println(
">>>>> Dispatching to " + msg.target + " "
+ msg.callback + ": " + msg.what
);
// 非常重要!将真正的處理工作交給message的target,即後面要講的handler
msg.target.dispatchMessage(msg);
// 還是日志。。。
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
// 下面沒看懂,同樣不影響了解
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);
}
// 回收message資源
msg.recycle();
}
}
}
當然,除了prepare()和loop()函數,Looper類還提供了一些有用的方法,比如Looper.myLooper()得到目前線程的Looper對象:
public static final Looper myLooper() {
// 在任意線程調用Looper.myLooper()傳回的都是那個線程的looper
return (Looper)sThreadLocal.get();
}
這邊可以看到,就是通過ThreadLocal變量拿到Looper對象的。還有getThread()得到Looper對象所在的線程,quit()方法來結束Looper線程。
對于Looper有以下總結:
1).每個線程最多隻能有一個Looper對象,并且此對象會存在ThreadLocal中;
2).每個Looper對象中會維護一個MessageQueue的消息隊列,loop()方法調用後線程會不斷地從隊列中取出消息并交由handler去處理;
3).Looper類可以将一個普通線程轉化為Looper線程。
Handler
下面問題是如何往MessageQueue上發送消息呢?這就要用到Handler!
Handler是什麼呢?handler的主要作用是往MessageQueue上添加和處理消息,當然隻會處理由自己發送的消息。Handler在建立的時候會關聯一個looper,預設的構造方法将關聯目前線程的looper,這個在源碼中很清晰:
public class handler {
final MessageQueue mQueue; // 關聯的MQ
final Looper mLooper; // 關聯的looper
final Callback mCallback;
// 其他屬性
public Handler() {
// 沒看懂,直接略過,,,
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == ) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 預設将關聯目前線程的looper
mLooper = Looper.myLooper();
// looper不能為空,即該預設的構造方法隻能在looper線程中使用
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
// 重要!!!直接把關聯looper的MQ作為自己的MQ,是以它的消息将發送到關聯looper的MQ上
mQueue = mLooper.mQueue;
mCallback = null;
}
// 其他方法
}
下面如果要在LooperThread中加入Handler:
public class LooperThread extends Thread {
private Handler handler1;
private Handler handler2;
@Override
public void run() {
// 将目前線程初始化為Looper線程
Looper.prepare();
// 執行個體化兩個handler
handler1 = new Handler();
handler2 = new Handler();
// 開始循環處理消息隊列
Looper.loop();
}
}
加入Handler執行個體的效果圖如下所示:
圖3 加入handler對象的Looper線程
是以可以看得出來:一個LooperThread隻能有一個Looper對象,但是可以用多個Handler。
Handler發送消息
有了handler就可以實用post(Runnable),postAtTime(Runnable,long),sendEmptyMessage(int),sendMessage(Message)等,看到這些API可以看出,發送兩種類型的消息:Message 和 Runnable,但是其實Runnable也是被封裝成Message的。
// 此方法用于向關聯的MQ上發送Runnable對象,它的run方法将在handler關聯的looper線程中執行
public final boolean post(Runnable r)
{
// 注意getPostMessage(r)将runnable封裝成message
return sendMessageDelayed(getPostMessage(r), );
}
private final Message getPostMessage(Runnable r) {
Message m = Message.obtain(); //得到空的message
m.callback = r; //将runnable設為message的callback,
return m;
}
通過handler發送Message有如下特點:
1.message.target即為該handler對象,這樣可以確定looper執行到該Message時能夠找到處理它的handler,即在loop()函數中的關鍵代碼:
2.post發出的消息,其callback為runnable對象;
Handler如何處理消息
消息的處理是通過核心方法dispatchMessage(Message msg)和鈎子函數handleMessage(Message msg)完成的,源碼如下:
// 處理消息,該方法由looper調用
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
// 如果message設定了callback,即runnable消息,處理callback!
handleCallback(msg);
} else {
// 如果handler本身設定了callback,則執行callback
if (mCallback != null) {
/* 這種方法允許讓activity等來實作Handler.Callback接口,避免了自己編寫handler重寫handleMessage方法。見http://alex-yang-xiansoftware-com.iteye.com/blog/850865 */
if (mCallback.handleMessage(msg)) {
return;
}
}
// 如果message沒有callback,則調用handler的鈎子方法handleMessage
handleMessage(msg);
}
}
// 處理runnable消息
private final void handleCallback(Message message) {
message.callback.run(); //直接調用run方法!
}
// 由子類實作的鈎子方法
public void handleMessage(Message msg) {
}
看到這裡,開發者可以實作handleMessage函數和Runnable對象的run()函數,以此來完成整個Handler機制!
Handler用處的總結:
1. handler可以在任意線程發送消息,并且這些消息會被添加到關聯的MessageQueue上。
圖4 handler發送消息到MessageQueue
2. handler是在它關聯的Looper線程中來處理消息的。
圖5 handler處理Message
這樣就解決了Android最經典的不能在其他非主線程中更新UI的問題:Android的主線程必是一個Looper線程,我們在其中建立的handler對象将預設關聯主線程的Looper對象(該Looper對象是由系統自動建立的),也就自然關聯到該Looper對象鎖維護的MessageQueue。其中一個最常見的實用案例就是,建立handler并将其引用傳給某個thread,當該thread完成耗時操作後,将實用handler将消息回發到消息隊列,再由loop()函數将消息彈出,交由handler的handleMessage(Message msg)的使用者自實作的鈎子函數來更新UI。
具體實作如圖6所示:
給一個執行個體代碼:
public class TestDriverActivity extends Activity {
private TextView textview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
textview = (TextView) findViewById(R.id.textview);
// 建立并啟動工作線程
Thread workerThread = new Thread(new SampleTask(new MyHandler()));
workerThread.start();
}
public void appendText(String msg) {
textview.setText(textview.getText() + "\n" + msg);
}
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
String result = msg.getData().getString("message");
// 更新UI
appendText(result);
}
}
}
public class SampleTask implements Runnable {
private static final String TAG = SampleTask.class.getSimpleName();
Handler handler;
public SampleTask(Handler handler) {
super();
this.handler = handler;
}
@Override
public void run() {
try { // 模拟執行某項任務,下載下傳等
Thread.sleep();
// 任務完成後通知activity更新UI
Message msg = prepareMessage("task completed!");
// message将被添加到主線程的MQ中
handler.sendMessage(msg);
} catch (InterruptedException e) {
Log.d(TAG, "interrupted!");
}
}
private Message prepareMessage(String str) {
Message result = handler.obtainMessage();
Bundle data = new Bundle();
data.putString("message", str);
result.setData(data);
return result;
}![這裡寫圖檔描述](http://img.blog.csdn.net/20150720232945900)
}