--- 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 中 > ![](https://i.imgur.com/mxVI5lh.png) ```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 這種方式就會變成了一種循環 > ![](https://i.imgur.com/fDza2tW.png) * 透過 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 > ![](https://i.imgur.com/JtqkS9L.png) * 從 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 才能正常接收、發送資訊 > ![](https://i.imgur.com/WAQAwIa.png) * 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 進階`