概述#
類 | 說明 |
---|---|
Handler | 真正處理事件的地方 |
Looper | 循環檢查是否有要傳輸的事件,從 MessageQueue 中獲取事件,並交給 Handler 處理(假如列隊為空就進入休眠) |
MessageQueue | 儲存需要做的事情,一般來說只允許保存相同類型的 Object、Message 除存的資料結構隊列 |
Message | 需要做的事件 |
一個 Thread 對應一個 Looper
一個 Looper 對應一個 MessageQueue
一個 MessageQueue 內有多個 Message
每個 Message 中最多對應一個 Handler 處理事件
Thread & Handler 是一對多的關係
Handler#
接受處理 Message
將 Message 存入 MessageQueue 中
// 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);
}
}
}
在上面分發事件有三種方法,並且 這三種分發方式有先後順序,只要前面被處理,就不會使用後面的方式處理
Message 本身的 callback
實現 Callback 接口
Override Handler#handleMessage
Function
透過 Handler 把信息入隊到 MessageQueue,方式有 Post & Send 兩種系列,並且可以控制發送的時間
Post 系列:把零散信息轉為 Message 再用 Send 傳出
函數 | 功能 |
---|---|
boolean post(Runnable r) | 直接發出信息 |
boolean postAtTime(Runnable, long updatetimeMillis) | 在固定(規定)時間再發出該條信息 |
Send 系列:參數直接是 Message |
函數 | 功能 |
---|---|
boolean sendEmptyMessage(int what) | 直接發送信息 |
boolean sendMessageArFrontOfQueue(Message msg) | 把消息發送到信息隊列最前面 |
boolean sendMessageAtTime(int what, long updatetimeMillis) | 在固定(規定)時間再發出該條信息 |
boolean sendMessageDelayed(Message msg, long delayMillis) | 延遲幾毫秒後發送該信息 |
Post 實現方式
// 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#
// 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);
}
處理 Message#
從 dispatchMessage 可看出它預設處理 Message 的順序
msg.callback (Runnable)
mCallback (interface)
handleMessage (method)
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);
}
}
MessageQueue & Message#
如其名,它是一個隊列 FIFO,它透過 本地方法 (Native) 內存指針創建 Queue
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#
MessageQueue 因為是 Queue 所以有所謂的 FIFO, 所以有隊列的功能
MessageQueue(boolean quitAllowed) {
mQuitAllowed = quitAllowed;
mPtr = nativeInit();
}
private native static int nativeInit();
MessageQueue 創建#
連接於 Looper 的建構函數,當 Looper 創建時 MessageQueue 就一同創建
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Looper 透過 MessageQueue 取得 Message#
// 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 沒有消息時讓使用者知道,並決定如何處理
// MessageQueue.java
public static interface IdleHandler {
// 返回true,會讓你設定的接口繼續存在
// 返回false則會移除你設定的接口
boolean queueIdle();
}
同樣分析 next 方法,可以看到一個 MessageQueue 最多設定 4 個 IdleHandler
// 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 - ThreadLocal#
最後 Looper 則是讓整個 Handler 機制循的動力,有 Looper 的推動 Handler 才能正常接收、發送信息
Looper 中包含了一個 MessageQueue(在構造函數中建構的)
// ava/android/os/Looper.java
public final class Looper {
// 私有函數
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
}
當你每創建一個線程就必須為這個線程準備 Looper,否則在 Handler 發送消息時就會 crush(上面有說到會檢查),創建主要有以下步驟
Looper 準備工作(prepare 函數)
創建 Handler 發送&接收消息
Looper 開始運作(loop 函數)
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();
}
}
ThreadLocal 這裡大概提及,ThreadLocal 也就是線程隔離,使用線程 Thread 作為 Key 儲存,而 Value 就是你要拷貝到每個線程的數據(每個子線程都持有一個數據)
//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));
}
}
當你建立一個 Handler 時,在 Handler construct 就會透過當前的線程取得 Looper
// 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 & Handler#
Looper 跟 Handler 的關係可以從 new Handler()這個構造函數中看出,它是透過 myLooper 方法,透過目前的線程在 ThreadLocal 中取得該當前線程所擁有的 Looper
// 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 ()
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");
}
主線程的 Looper 是不可以關閉的,並且使用類同步
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
Looper#loop
,首先取得目前線程所擁有的 Looper,再取出 Looper 內部有的 MessageQueue,最後無限循環整個消息對列
// 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 是一個泛型
// 前面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();
}
它使用目前呼叫它的 Thread.currentThread 作為 Key 存入,Value 是泛型
依照當前線程(currentThread),取的 Value