做過Android的都知道Message, MessageQueue, Handler和Looper,但知道不代表你了解它們。有時覺得用得很順手,但Android怎麼實作又說不上來,總覺得似懂非懂。不把它們攻破實在渾身不舒服。
先讓我們一句話總結,再開始分析。
Looper不斷擷取MessageQueue中的一個Message,然後交給Hanlder處理。
其實Message和Runnable可以一并壓入MessageQueue中,形成一個集合,後面将有所展現。
本文所涉及的代碼檔案以及路徑:
frameworks/base/core/java/android/os/Hanlder.java
frameworks/base/core/java/android/os/Message.java
frameworks/base/core/java/android/os/MessageQueue.java
frameworks/base/core/java/android/os/Looper.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/core/jni/android_os_MessageQueue.cpp
1、Message
android.os.Message定義了消息必要的描述和屬性資料。
public final class Message implements Parcelable {
public int what;
public int arg1;
public int arg2;
public Object obj;
public Messenger replyTo;
Bundle data;
Handler target;
Runnable callback;
......
}
請注意裡面的target和callback,後面将對此進行關聯。其中arg1和arg2是用來存放整型資料的,what用來儲存消息辨別,obj是Object類型的任意對象,replyTo是消息管理器,會關聯到一個handler。通常Message對象不是直接new出來,隻要調用handler中的obtainMessage方法來直接獲得Message對象。這也是Android推薦的做法。
/**
* Return a new Message instance from the global pool. Allows us to
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
synchronized (sPoolSync) {
if (sPool != null) {
Message m = sPool;
sPool = m.next;
m.next = null;
m.flags = 0; // clear in-use flag
sPoolSize--;
return m;
}
}
return new Message();
}
你看,如果池中沒有才會new一個Message。
2、MessageQueue
MessageQueue是一個final class,用來存放消息的消息隊列,它具有隊列的正常操作,包括:
- 建立隊列
-
MessageQueue(boolean quitAllowed) { mQuitAllowed = quitAllowed; mPtr = nativeInit(); }
-
由代碼可以看出,由構造函數和本地方法nativeInit()組成。其中,nativeInit()會在本地建立一個NativeMessageQueue對象,然後賦給MessageQueue中的成員變量,這一系列通過記憶體指針進行。private native static long nativeInit();
-
static jlong android_os_MessageQueue_nativeInit(JNIEnv* env, jclass clazz) { NativeMessageQueue* nativeMessageQueue = new NativeMessageQueue(); if (!nativeMessageQueue) { jniThrowRuntimeException(env, "Unable to allocate native queue"); return 0; } nativeMessageQueue->incStrong(env); return reinterpret_cast<jlong>(nativeMessageQueue); }
- 元素入隊
-
boolean enqueueMessage(Message msg, long when)
- 元素出隊
-
Message next()
- 元素删除
-
void removeMessages(Handler h, Runnable r, Object object)
void removeMessages(Handler h, int what, Object object)
- 銷毀隊列
-
銷毀隊列也需要用到本地方法,此處就不展開了。// Disposes of the underlying message queue. // Must only be called on the looper thread or the finalizer. private void dispose() { if (mPtr != 0) { nativeDestroy(mPtr); mPtr = 0; } }
3、Handler
Handler作為消息處理者,一是處理Message,二是将某個Message壓入MessageQueue中。Handler類中持有MessageQueue和Looper成員變量(後面再展現它們的作用):
public class Handler {
final MessageQueue mQueue;
final Looper mLooper;
final Callback mCallback;
final boolean mAsynchronous;
IMessenger mMessenger;
......
}
先讓我們focus Handler如何處理Message
public void dispatchMessage(Message msg)
public void handleMessage(Message msg)
一個對Message進行分發,一個對Message進行處理。
還記得開始的一句話總結麼?Looper從MessageQueue中取出一個Message後,首先會調用Handler.dispatchMessage進行消息分發。這裡雖然還沒涉及Looper的讨論,但可以先給出消息分發的代碼,具體在Looper類的loop方法中
public static void loop() {
......
for (;;) {
......
msg.target.dispatchMessage(msg);
......
}
}
好,回到Handler的dispatchMessage方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
通過代碼得知,預設情況下Handler的派發流程是:
- 如果Message中的callback不為空,通過callback來處理(開頭我們提到Message中有一個callback)
- 如果Handler的mCallback不為空,通過mCallback來處理
- 如果上面兩個都為空,才調用handleMessage來處理
其中mCallback為
public interface Callback {
public boolean handleMessage(Message msg);
}
而一般情況下,我們就是通過直接new Handler的方式重寫handleMessage來處理Message,這個Handler就是消息處理責任人。
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(Message msg) {
}
接着,Handler第二個作用是将某個Message壓入MessageQueue中。大家注意沒有,Message是Handler處理,而Message也是Handler壓入到MessageQueue中,既然這樣,為什麼不直接執行?其實這樣是展現程式設計的有序性,如果事件優先級較小,就需要排隊,否則馬上處理。
将Message壓入到MessageQueue中,能調用的主要的方法有:
public final boolean post(Runnable r)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean sendMessage(Message msg)
public final boolean sendEmptyMessage(int what)
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
post系列的方法會調用相應的sendEmptyMessage、sendEmptyMessageDelayed等方法,最終進入sendMessageAtTime中,然後調用enqueueMessage,把Message壓入隊列中。
由于post方法的參數是Runnable對象,是以Hander内部提供了getPostMessage方法把Runnable對象轉化為Message
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
最終,Handler形成了一個循環:Handler->MessageQueue->Message->Handler
4、Looper
Looper也是一個final class,并且持有一個MessageQueue,MessageQueue作為線程的消息存儲倉庫,配合Handler, Looper一起完成一系列操作。值得注意的是,還有一個final Thread和一個final ThreadLocal<Looper>的成員變量,其中ThreadLocal負責建立一個隻針對目前線程的Looper及其它相關資料對象,其它線程無法通路。
Looper類中的注釋還給了一個使用Looper的普通線程範例:
/*class LooperThread extends Thread {
* public Handler mHandler;
*
* public void run() {
* Looper.prepare();
*
* mHandler = new Handler() {
* public void handleMessage(Message msg) {
* // process incoming messages here
* }
* };
*
* Looper.loop();
* }
* }
*/
其實就是三個步驟:
- Looper.prepare()準備工作
- 建立消息處理的handler
- 調用Looper.loop()進入消息循環
看起來簡單吧?可是你能看出mHandler是怎樣把消息投遞到Looper所管理的MessageQueue中的麼?Looper在什麼時候建立呢?
先看一下Looper.prepare()到底做了什麼事情
public static void prepare() {
prepare(true);
}
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));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
首先通過sThreadLocal.get()判斷保證一個Thread隻能有一個Looper執行個體,最後new Looper完成Looper的執行個體化。同時MessageQueue就在Looper的構造函數中建立出來。
再來看handler的建立。還記得前面提到的Handler類中的成員變量麼?Handler中就持有一個Looper,這樣一來,Handler就和Looper關聯起來了。Handler一共有7個構造函數,看其中一個:
public Handler(Callback callback, boolean async) {
......
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 = callback;
mAsynchronous = async;
}
Looper中的myLooper()
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
這樣一來,Handler中的構造函數通過Looper.myLooper()擷取目前線程中的Looper執行個體,實際上就是Looper中的sThreadLocal.get()調用;然後把mLooper.mQueue賦給Handler的mQueue,最終Handler, Looper和MessageQueue就聯系起來了。後續Handler執行post/send系列的方法時,會将消息投遞給mQueue,也就是mLooper.mQueue中。一旦Looper處理到消息,它又從中調用Handler來進行處理。
最後看Looper.loop()。
它有兩個作用,一是建立處理消息的環境;二是循環處理消息。
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;
// 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();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// This must be in a local variable, in case a UI event sets the logger
Printer logging = me.mLogging;
if (logging != null) {
logging.println(">>>>> Dispatching to " + msg.target + " " +
msg.callback + ": " + msg.what);
}
msg.target.dispatchMessage(msg);
if (logging != null) {
logging.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(TAG, "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.recycleUnchecked();
}
}
由前面得知,myLooper()就是調用sThreadLocal.get()來擷取與之比對的Looper執行個體。me.mQueue驗證了每一個Looper中都自帶了一個MessageQueue。進入for循環後,開始從MessageQueue中取出一個消息(可能會阻塞),如果目前消息隊列中沒有Message,線程退出;否則分發消息。msg.target.dispatchMessage(msg)中的target就是一個Handler。最後消息處理完畢,進行回收。
平時我們在Activity中使用Handler處理Message時,為什麼看不到Looper呢?這隻能說Android偷偷為我們做了一些背後的工作。好了,UI線程要上場了。
5、ActivityThread
沒錯,ActivityThread就是我們熟悉的UI線程,它在應用程式啟動的時候由系統建立出來。先來看一下這個UI線程的main函數
public static void main(String[] args) {
......
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
......
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
有兩點與普通線程不一樣的地方。
普通線程隻要prepare就可以了,而主線程使用的是prepareMainLooper;普通線程生成一個與Looper綁定的Handler對象就行,而主線程是從目前線程中擷取Handler(thread.getHandler())。
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
其實prepareMainLooper也是調用prepare,隻是不讓該線程退出。經過prepare後,myLooper()就得到一個本地線程<ThreadLocal>的Looper對象,然後賦給sMainLooper,也就是UI線程的Looper。如果其它線程想獲得主線程的Looper,隻需調用getMainLooper()。
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
再來看thread.getHandler()。
其實ActivityThead内部有一個繼承Handler的H類
private class H extends Handler {
......
public void handleMessage(Message msg) {
......
}
......
}
final H mH = new H();
是以thread.getHandler()傳回的就是mH,這樣ActivityThread也有一個Handler處理各種消息了。
總結一下。
- 每個Thread隻對應一個Looper
- 每個Looper隻對應一個MessageQueue
- 每個MessageQueue有N個Message
- 每個Message最多指定一個Handler來處理
而Thread和Handler是一對多的關系。
到這裡,是不是對Message, MessageQueue, Handler和Looper有了更深的認識呢?
參考:
《深入了解Android核心設計思想》 林學森 編著