Handler概述
Handler在Android開發中非常重要,最常見的使用場景就是在子線程需要更新UI,用Handler來投遞消息到主線程執行UI更新操作。因爲Android系統的View是非線程安全的,所以需要在主線程更新UI。總的來說Handler就是用來做線程間通信,在不同線程之間傳遞消息。注:這篇文章所講到的Handler是在主線程創建的,主線程在開始的時候已經創建了默認的消息循環。後面的文章會講如何創建自己的消息循環。
消息循環主體結圖例分析
從圖中可以看出,四種顏色分別代表了四個對象,並且大致描述了幾個對象之間的關係,以及消息的流轉過程,首先Handler通過sendMessage將消息投遞給MessageQueue,Looper通過消息循環(loop)不斷的從MessageQueue中取出消息,然後消息被Handler的dispatchMessage分發到handleMessage方法消費掉。消息循環中涉及的重要對象
Handler
通過Handler的sendMessage等方法來投遞消息到MessageQueue,通過handleMessage來消費Message。Handler必須要有一個已經prepare好的Looper對象,也就是說必須調用了prepare方法(也包括prepareMainLooper方法),究其根本是初始化一個消息隊列,這一過程將在下文中詳細分析。
Looper
Looper負責從MessageQueue中取出消息,然後通過執行message.target.dispatchMessage()消費掉這個消息,這裏的target就是Handler。
MessageQueue
消息隊列,管理Handler投遞過來的消息。
Message
用來承載數據的消息,最終被Handler消費掉。
UML類圖分析
通過上面的類圖可以清晰的瞭解各個類之間的關係。然後再來分析一下源碼。Handler的創建
public Handler(Callback callback, boolean async) {
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 = callback;
mAsynchronous = async;
}
在上面這段代碼中,首先是檢查是否存在潛在的內存泄漏,如果該類是匿名內部類,或者是成員類且沒有static修飾符時那麼打印一個內存泄漏風險警告。這是由於這種類型的class持有外部類的this引用,可能導致外部類無法釋放。接下來就是對成員變量mLooper賦值,在文章開頭就提到過,這篇文章中提到的handler對象時在主線程(UI線程)中創建,而Android主線已經有一個消息隊列了,所以直接將mLooper.mQueue賦給Handler的mQueue。
那麼主線程中的消息隊列是怎麼創建的呢?
看下面的關鍵代碼,UI線程在創建的時候,會調用prepareMainLooper()這個方法,創建一個不退出的消息隊列。所以prepareMainLooper這個方法自己永遠也不要調用,它是系統調用的,如果我們需要用自己的消息隊列呢?那麼就應該調用prepare()方法。
public static void prepare() {
prepare(true);
}
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
將looper對象裝入ThreadLocal中,Handler就是從它裏面取出looper對象的
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
//創建消息隊列
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
消息怎麼被消費的呢?
整個消息循環系統中的幾個重要部件的創建都已經明白了,那麼消息時怎麼循環起來的,又是如何消費的呢?來看看下面是loop源碼的一部分關鍵代碼。代碼非常簡單易懂,就是從消息隊列中取出消息,然後通過msg.target.dispatchMessage(msg)將消息投遞到Handler。
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 block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
msg.target.dispatchMessage(msg);
msg.recycleUnchecked();
}
}
消息傳遞的終點
當消息循環中取出的消息被再次傳遞給Handler的時候,這個消息就走到了生命的盡頭(並不代表對象銷燬,有一個消息池來回收消息),從dispatchMessage方法可以看出,消息最終的歸宿有三個,一是消息自身的callback接口,二是handler的callback接口,最後是handleMessage接口。
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
總結
通過前面從不同方向對Android的Handler消息循環進行分析,基本結構和原理已經清晰,但是還遠遠不夠,在接下來的文章中,將會對前面提到的潛質內存泄漏做一個詳細的分析。轉載自:vjson.com