Handler與Looper方法源碼解析
概述
先看一個Android中的HandlerThread是如何使用Looper的。
public class HandlerThread extends Thread {
@Override
public void run() {
......
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
......
Looper.loop();
......
}
public boolean quit() {
Looper looper = getLooper();
if (looper != null) {
looper.quit();
return true;
}
return false;
}
}
在線程的run方法中調用Looper的prepare()方法進行準備工作,準備之後就可以通過Looper.myLooper獲取到當前的線程的Looper了。使用然後調用loop方法進入循環處理。使用的時候非常簡單。接下來分析Looper的實現。
而且可以quit來退出線程,quit方法中獲取當前線程的looper,不為null會調用looper對象quit方法退出。
Looper
prepare方法
先分析一下靜態的方法prepare。
public final class Looper {
······
public static void prepare() {
prepare(true);
}
······
}
對外的靜態方法prepare調用私用的帶有參數的prepare方法。
public final class Looper {
······
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));
}
······
}
參數quitAllowed標識是否允許looper退出。
首先調用sThreadLocal參數獲取是否有Looper。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
sThreadLocal線程的本地對象,用於保存線程相關的變數。如果從sThreadLocal獲取Looper對象不為null,說明線程已經綁定了Looper,直接拋出異常。如果為從sThreadLocal獲取的Looper對象為null,就創建一個Looper,並設置到sThreadLocal中。
public final class Looper {
······
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
······
}
Looper的構造方法中創建MessageQueue,用於保存消息處理。並保存當前的線程到mThread變數中。
總結一下:
- Looper.prepare()會調用私有帶有參數的prepare方法-在私有的帶有參數的prepare方法中會創建Looper對象,並添加到線程的本地對象中。-Looper的構造方法中會創建MessageQueue消息隊列對象。
loop方法
public final class Looper {
.......
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasnt called on this thread.");
}
final MessageQueue queue = me.mQueue;
······
}
.......
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
......
}
loop靜態方法中,首先調用myLooper獲取當前的線程的looper。如果為null,說明線程未綁定Looper,直接拋出異常。如果不為null,獲取Looper中的消息隊列MessageQueue。
public final class Looper {
.......
public static void loop() {
······
for (;;) {
Message msg = queue.next(); // 消息隊列為空,將一直阻塞
if (msg == null) {
return;
}
······
}
·····
}
}
接著是死循環,一直從消息隊列中獲取消息message。當msg為null說明MessageQueue正在退出,這裡就直接從死循環中退出。接著分析。
public final class Looper {
public static void loop() {
for (;;) {
······
try {
msg.target.dispatchMessage(msg);
} finally {
}
······
}
······
}
}
消息對象的target對象實際為Handler對象。也就是調用了Handler的dispatchMessage對象來處理消息。
public final class Looper {
······
public static void loop() {
······
for (;;) {
······
msg.recycleUnchecked();
}
······
}
······
}
最後是調用msg的recycleUnchecked。也是就回收msg,以備下次使用。
總結一下Looper.loop()方法:
-獲取當前線程綁定的Looper的消息隊列。
-死循環中不斷從消息隊列中取出Message來處理。有消息就調用消息的target(Handler對象)的來處理。-最後回收Message。quit方法
public final class Looper {
······
public void quit() {
mQueue.quit(false);
}
······
}
Looper的quit方法會調用消息隊列的quit方法。
分段閱讀MessageQueue的quit方法。
public final class MessageQueue {
······
void quit(boolean safe) {
if (!mQuitAllowed) {
throw new IllegalStateException("Main thread not allowed to quit.");
}
synchronized (this) {
if (mQuitting) {
return;
}
mQuitting = true;
if (safe) {
removeAllFutureMessagesLocked();
}
······
}
}
······
}
MessageQueue方法中先檢測mQuitAllowed用來判斷是否支持退出,主線程的looper是不支持的。
檢測mQuitting值來判斷MessageQueue是否已經退出了。如果mQuitting為true,說明MessageQueue已經退出,就直接返回了。
如果mQuitting是false,接著執行,設置mQuitting = true,接著safe為true,說明是安全退出,會調用 removeAllFutureMessagesLocked()。我們來分析一下removeAllFutureMessagesLocked()
private void removeAllFutureMessagesLocked() {
final long now = SystemClock.uptimeMillis();
Message p = mMessages;
if (p != null) {
//比較當前的message的執行的時間是否大於當前的時間。如果是就直接的移除所有的消息。
if (p.when > now) {
removeAllMessagesLocked();
} else {
Message n;
//循環比較獲取時間點大於當前的時間點的消息。
for (;;) {
n = p.next;
if (n == null) {
return;
}
if (n.when > now) {
break;
}
p = n;
}
p.next = null;
//循環刪除消息隊列中時間點大於當前時間點的消息。
do {
p = n;
n = p.next;
p.recycleUnchecked();
} while (n != null);
}
}
}
此方法主要是根據刪除執行的時間點大於當前時間點的消息。我接著分析MessageQueue的quit方法。
void quit(boolean safe) {
······
synchronized (this) {
······
if (safe) {
removeAllFutureMessagesLocked();
} else {
removeAllMessagesLocked();
}
nativeWake(mPtr);
}
}
如果safe為false,不是安全退出,直接調用removeAllMessagesLocked()刪除回收所有的Message。
總結一下Looper的quit方法:
-Looper的quit方法會調用消息隊列MessageQueue的quit方法
-MessageQueue的quit方法中,如果是非安全退出,直接移除所有的消息。如果是安全退出直接移除執行時間點大於當前時間點的Message。主線程中的Looper
主線程中的消息的管理也是通過Looper來實現的。它與普通線程的Looper不同的是有特殊的方法,但原理基本一致。
public final class Looper {
private static Looper sMainLooper; // guarded by Looper.class
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
}
-主線程的Looper有單獨的變數sMainLooper保存。
-prepareMainLooper方法用於準備主線的Looper,它是在ActivityThread的main方法中調用的,也就是創建主線程時就會創建了。-getMainLooper方法獲取主線程的Looper。Handler
A Handler allows you to send and process Message and Runnable objects associated with a thread』s MessageQueue. Each Handler instance is associated with a single thread and that thread』s message queue.
從描述可以總結出Handler一些特性:
1.每個Handler實例都會與一個線程以及線程的messageQueue關聯。
2.發送消息。3.處理消息,處理Runnable。Handler與Looper的關係圖: