---
title: 'Android Handler 消息機制'
disqus: kyleAlien
---
Android Handler 消息機制
===
## OverView of Content
如有引用參考請詳註出處,感謝 :smile:
Android 是以消息推動系統的機制,所以我們要好好了解 Handler 機制,以下會以使用 Handler 分析源碼 來下手;這篇是分析 Java 層的消息機制
[TOC]
## Android Handler 概述
**由於 Android 是 ++消息驅動++ 的系統**,所以要先來介紹 Handler,Handler 機制主要有分為 4 個組成
| 類 | 說明功能 |
| -------- | -------- |
| [**Handler**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/Handler.java) | 使用者接收、傳送事件的句秉 |
| [**Looper**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/Looper.java) | 循環檢查是否有要傳輸的事件,從 MessageQueue 中獲取事件,並交給 Handler 處理(假如列隊為空就進入休眠) |
| [**MessageQueue**](https://android.googlesource.com/platform/frameworks/base/+/0e2d281/core/java/android/os/MessageQueue.java) | 儲存需要做的事情,**一般來說止允許保存相同類型的 Object**、Message 除存的數據結構為 [**佇列**](https://hackmd.io/@AlienHackMd/rkkpuEhzU) |
| [**Message**](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/Message.java) | 需要做的事件、要傳遞的訊息 |
* 其實一開始會很難發現 Handler & Thread 之間的關係,我們可以先看看這幾個結論在看看程式如何實現它
1. 一個 Thread 對應一個 Looper
2. 一個 Looper 對應一個 MessageQueue
3. 一個 MessageQueue 內有多個 Message
4. **每個 Message 中最多對應一個 Handler 處理事件**
> **==Thread & Handler 是一對多的關係==**
### [Handler](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/Handler.java)
* 應用開發時常使用到 Handler 類,它主要有兩個做用
1. 接收 **處理** Message
2. 將 Message **存入** MessageQueue 中
> 
```java=
// Handler.java
public class Handler {
...
final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback;
...
public interface Callback {
boolean handleMessage(@NonNull Message msg);
}
// 通常用來給使用者 Override 處理事件
public void handleMessage(@NonNull Message msg) {
}
// 分發事件,有三種方式
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
}
```
* 在上面分發事件有三種方法,並且 **這三種分發方式有 ^1^ 先後順序**,只要前面被處理,就不會使用後面的方式處理
1. Message 本身的 callback
2. 實現 Callback 接口
3. Override `Handler#handleMessage` Function
這種方式就會變成了一種循環
> 
* 透過 Handler 把訊息壓到 MessageQueue,**方式有 Post & Send 兩種系列,並且可以 ^2^ 控制發送的時間**,以下寫幾個常用的
1. Post 系列:把零散訊息轉為 Message 再用 Send 傳出
| 函數 | 功能 |
| -------- | -------- |
| boolean post(Runnable r) | 直接發出訊息 |
| boolean postAtTime(Runnable, long updatetimeMillis) | 在固定(規定)時間再發出該條訊息 |
2. Send 系列:參數直接是 Message
| 函數 | 功能 |
| -------- | -------- |
| boolean sendEmptyMessage(int what) | 直接發送訊息 |
| boolean sendMessageArFrontOfQueue(Message msg) | 把消息發送到訊息隊列最前面 |
| boolean sendMessageAtTime(int what, long updatetimeMillis) | 在固定(規定)時間再發出該條訊息 |
| boolean sendMessageDelayed(Message msg, long delayMillis) | 延遲幾毫秒後發送該訊息 |
* Post 實現方式如下
```java=
// Handler.java
public class Handler {
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
// 包裝 callback 再傳出
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain(); // 取得 Message 資源,避免不斷創建,可以復用資源
m.callback = r; // 直接設定 Runnable 回調函數
return m;
}
// 最後透過計算 當前時間 + 延長實現,之後就呼叫 sendMessageAtTime 函數
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
// 在規定時間發送消息
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
// 若是該 Thread 並沒有設定 MessageQueue 則會拋出錯誤
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
}
```
### 發送訊息方法
| 名稱 | 參數 : 回傳 | 解釋 |
| -------- | -------- | -------- |
| post | Runnable : boolean | 接收一個 Runnable 對象作為 Message |
| postAtTime | Runnable, long : boolean | 接收一個 Runnable 對象作為 Message,並在等待的規定時間發送 Message |
| sendEmptyMessage | int : boolean | 發送一個使用者規定的 int 訊息,在由使用者自己處理 |
| sendMessageAtTime | Messge, int : boolean | 發送一個使用者規定的 int 訊息,在由使用者自己處理 |
| sendMessageDelayed | Messge, long : boolean | 在等待的規定時間後 (延遲) 發送 Message |
### Post & Send
* 從上面可以看出上面主要有 Post & Send
* 而他們的差別在 **Send 內直接發送 Message 訊息** 在設定進 Message 內的屬性 what,**Post 則是包裝過後在調用 Send 的方法**,**其 ++本質是一樣的++**
```java=
// Send ...
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}
// Post ...
public final boolean post(Runnable r)
{
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
// 最終都會發至 sendMessageAtTime
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) { // 1.
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
```
1. 一般來說每個 Thread 都要有一個 MessageQueue 才可以處理 Message
### 處理 Message
* 可透過重載 Handler 中的 `dispatchMessage`、`handleMessage`這兩個函數作為 Handler 處理 Message
> 
* 從 dispatchMessage 可看出**它預設處理 Message 的順序**
1. msg.callback (Runnable)
2. mCallback (interface)
3. handleMessage (method)
```java=
public void handleMessage(Message msg) {
// 使用者覆寫
}
/**
* Handle system messages here.
*/
public void dispatchMessage(Message msg) {
// callback 優先及最高
if (msg.callback != null) { // msg.callback is Runnable
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
```
### runWithScissors 傳同步訊息
* 舉例:以下是 WMS 在初始化時就使用 ([**DisplayThread**](https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/DisplayThread.java)) Handler#runWithScissors 這個函數來達到先執行 Runnable 任務的功能 (如果不先創建 WMS 則後面使用則會出問題)
```java=
// DisplayThread.java
public final class DisplayThread extends ServiceThread { // ServiceThread 會初始化 Loop
private static DisplayThread sInstance;
private static Handler sHandler;
... 省略部分
private static void ensureThreadLocked() {
if (sInstance == null) {
sInstance = new DisplayThread();
sInstance.start();
sInstance.getLooper().setTraceTag(Trace.TRACE_TAG_SYSTEM_SERVER);
// 創建 Handler 對象 (其中的 Looper 是父類創建並初始化)
sHandler = new Handler(sInstance.getLooper());
}
}
public static Handler getHandler() {
synchronized (DisplayThread.class) {
ensureThreadLocked();
return sHandler;
}
}
}
// ----------------------------------------------------------
// WindowManagerService.java
private static WindowManagerService sInstance;
static WindowManagerService getInstance() {
return sInstance;
}
@VisibleForTesting
public static WindowManagerService main(final Context context, final InputManagerService im,
final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
ActivityTaskManagerService atm, DisplayWindowSettingsProvider
displayWindowSettingsProvider, Supplier<SurfaceControl.Transaction> transactionFactory,
Supplier<Surface> surfaceFactory,
Function<SurfaceSession, SurfaceControl.Builder> surfaceControlFactory) {
// getHandler 就是 Handler 對象
DisplayThread.getHandler().runWithScissors(() ->
// 創建 WindowManagerService 對象
sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
atm, displayWindowSettingsProvider, transactionFactory, surfaceFactory,
surfaceControlFactory), 0);
return sInstance;
}
```
* 這裡的重點是 Handler 中的 **runWithScissors 函數:** ^1^ 比對 Looper 若是就是 Handler 中的 Thread,則直接執行,^2^ 創建 BlockingRunnable 對象 (主要分析 BlockingRunnable)
```java=
// Handler.java
public class Handler {
... 省略部分
final Looper mLooper;
public final boolean runWithScissors(@NonNull Runnable r, long timeout) {
// 判空
if (r == null) {
throw new IllegalArgumentException("runnable must not be null");
}
// 時間檢查
if (timeout < 0) {
throw new IllegalArgumentException("timeout must be non-negative");
}
// 若當前 Handler 使用的 Looper (mLooper) 就是 Looper#myLooper
// 也就是比對 Thread (因為一個 Thread 只有一個 Looper)
if (Looper.myLooper() == mLooper) { // 使用到當前 Thread
r.run(); // 直接執行
return true;
}
// 創建堵塞 Runnable 對象
BlockingRunnable br = new BlockingRunnable(r);
// 分析 postAndWait 方法
return br.postAndWait(this, timeout);
}
}
```
* BlockingRunnable 是 Handler 中的內部類
```java=
// Handler.java
public class Handler {
private static final class BlockingRunnable implements Runnable {
private final Runnable mTask;
private boolean mDone;
public BlockingRunnable(Runnable task) {
mTask = task;
}
@Override
public void run() {
try {
mTask.run(); // 跑使用者的任務
} finally {
synchronized (this) {
mDone = true;
notifyAll(); // 喚醒當前對象所有的鎖
}
}
}
public boolean postAndWait(Handler handler, long timeout) {
// 先丟入任務 Queue,判斷是否成功
if (!handler.post(this)) {
return false;
}
synchronized (this) {
if (timeout > 0) {
// 計算到期時間
final long expirationTime = SystemClock.uptimeMillis() + timeout;
while (!mDone) {
long delay = expirationTime - SystemClock.uptimeMillis();
if (delay <= 0) {
return false; // timeout
}
try {
wait(delay); // wait 指定 delay 的時間後喚醒當前對象
} catch (InterruptedException ex) {
}
}
} else {
while (!mDone) {
try {
wait(); // wait 當前對象
} catch (InterruptedException ex) {
}
}
}
}
return true;
}
}
}
```
## MessageQueue & Message
* 如其名,它是一個**數據結構佇列 FIFO**,它透過 ==**本地方法 (Native) 內存指針創建 Queue**==
```java=
private native static long nativeInit();
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
```
### Queue 方法
| 名稱 | 參數 : 回傳 | 解釋 |
| -------- | -------- | -------- |
| enqueueMessage | Message, long : boolean | 在指定時間內壓入佇列中 |
| next | void : Message | 元素拉出佇列 |
| removeMessages | Handler, int, Object : void | 移除特定元素 |
| removeMessages | Handler, Runnable, Object : void | 移除特定元素 |
### [MessageQueue](https://android.googlesource.com/platform/frameworks/base/+/0e2d281/core/java/android/os/MessageQueue.java)
* MessageQueue 因為是 Queue(數據結構) 所以有所謂的 FIFO,MessageQueue 有以下功能
1. 新建列隊
由建構函數 中的 **nativeInit** 方法組成
```java=
// /android/os/MessageQueue.java
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
private native static int nativeInit();
```
2. 元素入隊列 **enqueueMessage**
```java=
// /android/os/MessageQueue.java
boolean enqueueMessage(Message msg, long when) {
...
}
```
3. 元素出隊列 **next**
```java=
// /android/os/MessageQueue.java
Message next() {
...
}
```
4. 刪除元素
```java=
// /android/os/MessageQueue.java
void removeMessages(Handler h, int what, Object object) {
...
}
void removeMessages(Handler h, Runnable r, Object object) {
...
}
```
5. 銷毀列隊,透過本地函數 nativeDestory 銷毀一個 MessageQueue
```java=
private native static void nativeDestroy(int ptr);
```
### MessageQueue 創建
> 連接於 Looper 的建構函數,**==當 Looper 創建時 MessageQueue 就一同創建==**
```java=
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
```
### Looper 透過 MessageQueue 取得 Message
* Looper 透過 MessageQueue#next 函數,就可以取得下一條要發送的訊息
:::warning
* next 函數是一個無限循環的函數,所以取不到訊息可能會 Block
:::
```java=
// MessageQueue.java
Message next() {
// 若已經被 depose mPtr 就會被設定為 0
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
// 下一個訊息的時間
int nextPollTimeoutMillis = 0;
// 進入無限循環,也就是說 next 會導致 block
for (;;) {
... 省略部分
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null; // 上一個訊息
Message msg = mMessages; // 當前訊息
if (msg != null && msg.target == null) { // target 就是 Handler
// 找到一個可發送的 Message
do {
prevMsg = msg;
msg = msg.next; // 切換到下一個 Message
} while (msg != null && !msg.isAsynchronous());
}
// 再次判斷 Message
if (msg != null) {
// 判斷時間
if (now < msg.when) { // 該訊息的時間還沒到
// Next message is not ready. Set a timeout to wake up when it is ready.
// 計算剩餘時間
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
// 時間到,並且有 Message
mBlocked = false;
if (prevMsg != null) {
prevMsg.next = msg.next; // 上一個 Message 就是當前 Message
} else {
mMessages = msg.next; //切換到下一個要用的 Message
}
// 斷開連結 !! 好讓 GC 偵測到後回收 !!! (可達性分析)
msg.next = null;
... debug 訊息
msg.markInUse(); // 標記該 Message 已經被使用過
return msg;
}
} else {
// No more messages.
nextPollTimeoutMillis = -1;
}
// Process the quit message now that all pending messages have been handled.
if (mQuitting) { // 檢查是否退出
dispose();
return null;
}
... 省略 IdleHandler (下一小節會說明)
}
... 省略部分
}
```
### IdleHandler - 偵測閒置
* IdleHandler 是 MessageQueue 內的一個 interface,它可以在 MessageQueue 沒有消息時讓使用者知道,並決定如何處理
```java=
// MessageQueue.java
public static interface IdleHandler {
// 返回 true,會讓你設定的接口繼續存在
// 返回 false 則會移除你設定的接口
boolean queueIdle();
}
```
* 同樣分析 next 方法,可以看到 **一個 MessageQueue 最多設定 4 個 IdleHandler**
```java=
// MessageQueue.java
Message next() {
// 若已經被 depose mPtr 就會被設定為 0
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
int pendingIdleHandlerCount = -1; // -1 only during first iteration
// 下一個訊息的時間
int nextPollTimeoutMillis = 0;
// 進入無限循環,也就是說 next 會導致 block
for (;;) {
... 省略部分
synchronized (this) {
... 省略部分
// 檢查是否有設置 IdleHandler
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
mBlocked = true;
continue;
}
// 最多設置 4 個 Idle Handler
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 循環
for (int i = 0; i < pendingIdleHandlerCount; i++) {
final IdleHandler idler = mPendingIdleHandlers[i];
mPendingIdleHandlers[i] = null; // release the reference to the handler
boolean keep = false;
try {
// 當沒有訊息時通知接口
keep = idler.queueIdle();
} catch (Throwable t) {
Log.wtf(TAG, "IdleHandler threw exception", t);
}
// 返回 false 就移除
if (!keep) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
... 省略部分
}
}
```
## Looper
* 它是組成消息的重要關鍵 (Handler、Message、MessageQueue),**它的角色是==驅動==**
| 名稱 | 參數 : 回傳 | 解釋 |
| -------- | -------- | -------- |
| myLooper | void : Looper | 以當前線程為主,取得當前 Thread 的 Looper |
| getMainLooper | void : Looper | 取得主線程的 Looper |
### [Looper](https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/Looper.java) - [ThreadLocal](https://android.googlesource.com/platform/libcore/+/1f07ea2/luni/src/main/java/java/lang/ThreadLocal.java)
* 最後 Looper 則是讓整個 Hanler 機制循的動力,有 Looper 的推動 Handler 才能正常接收、發送資訊
> 
* Looper 中包含了一個 MessageQueue(在建構函數中建構的)
```java=
// ava/android/os/Looper.java
public final class Looper {
// 私有函數
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
}
```
* 當你每創建一個線程就必須為這個線程準備 Looper,否則在 Handler 發送消息時就會 crush (上面有說到會檢查),創建主要有以下步驟
1. Looper 準備工作(prepare 函數)
2. 創建 Handler 發送 & 接收消息
3. Looper 開始運作(loop 函數)
```java=
class LooperThread extends Thread {
private Handler handler;
public void run() {
// 1
Looper.prepare();
// 2.
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
//... 處理 Message
}
}
// 3.
Looper.loop();
}
}
```
:::success
* 不需要準備 Thread ?
其實 Thread 是也是有使用,不過它由 ThreadLocal 做管理,細節可以參考另外一篇 [**文章**](https://hackmd.io/7fBX6uEtQt6AzCpuBWTHMQ?view)
:::
* ThreadLocal 這裡大概提及,ThreadLocal 也就是線程隔離,使用線程 Thread 作為 Key 儲存,而 Value 就是你要拷貝到每個線程的數據(每個子線程都持有一個數據)
```java=
// /android/os/Looper.java
public final class Looper {
// 拷貝線程的數據是 Looper
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) // 一個線程只能 prepare 一次
throw new RuntimeException("Only one Looper may be created per thread");
}
// 為當前 Thread 設定 Looper
sThreadLocal.set(new Looper(quitAllowed));
}
}
```
* 這裡要注意 ^1^ ThreadLocal 是泛型,^2^ 在 Looper 裡面就是一個靜態變數
* 當你建立一個 Handler 時,在 Handler construct 就會透過當前的線程取得 Looper
```java=
// Handler
public Handler(@Nullable Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
// -----------------------------------------------------------------
// Looper
public static @Nullable Looper myLooper() {
// sThreadLocal 是靜態的,會透過當前 Thread 作為 Key 取得 Looper
return sThreadLocal.get();
}
```
### Looper & WorkThread
> 當一個普通線程要使用 Handler 時 **必須要有 Looper 的預前準備工作**
```java=
public class MyThread extends Thread {
private Handler handler;
@SuppressLint("HandlerLeak")
@Override
public void run() {
Looper.prepare(); //"1. "
handler = new Handler() { //"2. "
@Override
public void handleMessage(@NonNull Message msg) {
}
};
Looper.loop(); //"3. "
}
}
```
1. Looper 預前準備
```java=
//"a. "
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
// 只要內部有就不會創建 Loop
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//"b. "
sThreadLocal.set(new Looper(quitAllowed));
}
//Looper Constract...
private Looper(boolean quitAllowed) {
//"c. "
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
```
> **a.** 它有一個很重要的屬性 **static final ThreadLocal**,它是一個 **靜態變量**,意味著每個線程共享此屬性,但 **[ThreadLocal](https://hackmd.io/7Ru0TE45Tnm1LEUqx4qe-A#ThreadLocal-%E7%B7%9A%E7%A8%8B%E9%9A%94%E9%9B%A2) 是特殊的變量,==讓每一個 Thread 都有一個 Looper 對象==**
> **b.** 可看出 **prepare 時它內部會自己創建一個 Looper 對象**,並且 Looper 的建構函數也是私有的
> **c.** Looper 被創建時就會**自己準備一個 MessageQueue**
2. 創建處理消息的 Handler
3. Looper 開始循環運作
### Looper & Handler
Looper 跟 Handler 的關係可以從 **new Handler() 這個==建構函數==** 中看出,它是**透過 myLooper 方法,透過目前的線程在 ThreadLocal 中 ++取得該當前線程所擁有的 Looper++**
> 這也就是上面在準備時為何要調用 Looper.prepare() 這個方法,如果沒準備就不一定會有 Looper
```java=
// Handler construct
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
... 忽略
// 取得當前線程的 Loop
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...
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
```
### Looper & UI Thread
* Android 中 Activity 的主線程是 ActivityThread's main() (frameworks/base/core/java/android/app/ActivityThread.java)
```java=
public static void main(String[] args) {
...
Looper.prepareMainLooper(); //"1. "
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
//"2. "
sMainThreadHandler = thread.getHandler();
}
...
// End of event ActivityThreadMain.
...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
```
1. 主線程的 Looper 是不可以關閉的,並且使用類同步
```java=
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 Looper sMainLooper; // guarded by Looper.class
```
> sMainLooper = myLooper(); **把目前的 Thread 作為內部靜態類維護,並可以透過,getMainLooper ==隨時==取得**
>
```java=
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
```
* **這樣主線程可以隨時訪問其他 Looper (透過 myLooper() 方法)**
2. 一般線程必須自己建造 Handler 處理訊息,不過其實 **ActivityThread 內部已經有自己的 Handler 實現** (並且不能 Override)
```java=
// ActivityThread.java
final Handler getHandler() {
return mH;
}
// 屬性...
final H mH = new H();
// Handler 實現
private class H extends Handler {
...
}
```
3. Looper#loop,首先取得目前線程所擁有的 Looper,再取出 Looper 內部有的 MessageQueue,最後無限循環整個消息對列
```java=
// Looper.java
public static void loop() {
final Looper me = myLooper();
...
final MessageQueue queue = me.mQueue;
...
for (;;) {
//
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
...
try {
// 解決是誰再呼叫 dispatchMessage,target 為 MessageQueue 中的 Handler
msg.target.dispatchMessage(msg);
end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis();
} finally {
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
...
msg.recycleUnchecked();
}
}
```
## ThreadLocal
* **ThreadLocal 的功能主要是做到線程隔離 (用線程隔離數據)**,**簡單來說可以把 ThreadLocal 當作一個 Map (但實際來說它並不是 Map),它的 Key 是 `Thread`,Value 是一個`泛型`**
* 詳細 ThreadLocal 分析有寫在 [**Java 多線程-進階**](https://hackmd.io/7Ru0TE45Tnm1LEUqx4qe-A?view#ThreadLocal-%E7%B7%9A%E7%A8%8B%E9%9A%94%E9%9B%A2)
```java=
// 前面 Looper.prepare() 內部就有使用到 set() 方法
public void set(T value) {
Thread t = Thread.currentThread(); //"1. "
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
// 前面 Handler() 建構函數內部就有使用到 get() 方法
public T get() {
Thread t = Thread.currentThread(); //"2. "
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
```
1. 它使用目前呼叫它的 Thread.currentThread 作為 Key 存入,Value 是泛型
2. 依照當前線程 (currentThread),取的 Value
* **消息機制就是通過每個 Thread 儲存不同的 Looper 在 ThreadLocal 中**,當有需要時就已 Thread 作為 key 來取得 Looper
## 結論
Handler & Thread
* 從上面可以看出 Handler & Thread 的關係是建立在,==**ThreadLocal 取得 Looper,而 Handler 建構函數又取得當前 Thread**==
* **一個 Thread 對應一個 Looper,一個 Looper 對應一個 MessageQueue**
## Appendix & FAQ
:::info
:::
###### tags: `Android 進階`