回轉壽司你一定吃過!——Android訊息機制(處理)
這是“Android訊息機制”系列的第三篇文章,系列文章目錄如下:
回轉壽司的故事已經編不下去了,壽司店不會規定消費者應該如何享用壽司。但我們之所以傳送訊息,不就是為了想用自己的方式來處理訊息嗎。
處理訊息的起點
先回憶一下分發訊息的關鍵函式Looper.loop()
,原始碼如下:
//省略了非關鍵程式碼 public static void loop() { ... //拿訊息的無限迴圈 for (; ; ) { //從隊頭拿訊息 Message msg = queue.next(); // might block ... //分發訊息 msg.target.dispatchMessage(msg); ... }
還記得系列文章第一篇中留下的懸念嗎?在構造訊息時,為啥訊息物件持有構造它的Handler物件?現在可以回答這個問題了:
Looper
遍歷訊息時,把訊息交給與其對應的Handler
處理。交接訊息是通過呼叫Handler.dispatchMessage()
,這是訊息分發的終點,也是處理訊息的起點。
處理訊息的方式
移步到Handler.dispatchMessage()
:
/** * Handle system messages here. */ public void dispatchMessage(Message msg) { //處理方式1 if (msg.callback != null) { handleCallback(msg); } else { //處理訊息方式2 if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } //處理訊息方式3 handleMessage(msg); } }
- 可以清楚的看到有三種處理訊息的方式
-
直接執行
Message
中Runnable.run()
。
public class Handler{ ... private static void handleCallback(Message message) { message.callback.run(); } ... } public final class Message implements Parcelable { ... /*package*/ Runnable callback; ... }
Message
的Runnable
是哪來的?
/** * Causes the Runnable r to be added to the message queue. * The runnable will be run on the thread to which this handler is * attached. * * @param r The Runnable that will be executed. */ public final boolean post(Runnable r) { returnsendMessageDelayed(getPostMessage(r), 0); } //將 Runnable 包裝成 Message private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
每次呼叫Handler.post(Runnable r)
時,Handler
都會將Runnable
包裝成Message
,這樣Runnable
和Message
就可以共用訊息分發邏輯,但它們的處理邏輯會有所不同,如果訊息中帶有Runnable
則會最優先被處理,處理方式是直接呼叫Runnable.run()
-
Handler.Callback
方式
/** * Callback interface you can use when instantiating a Handler to avoid * having to implement your own subclass of Handler. * * @param msg A {@link android.os.Message Message} object * @return True if no further handling is desired */ public interface Callback { public boolean handleMessage(Message msg); }
除了繼承Handler
這種最常見的處理訊息方式外,我們還可以通過Handler.Callback
來定義處理訊息的方式:
/** * Constructor associates this handler with the {@link Looper} for the * current thread and takes a callback interface in which you can handle * messages. * * If this thread does not have a looper, this handler won't be able to receive messages * so an exception is thrown. * * @param callback The callback interface in which to handle messages, or null. */ public Handler(Callback callback) { this(callback, false); }
-
過載
handleMessage()
/** * Subclasses must implement this to receive messages. */ public void handleMessage(Message msg) { }
通常我們是通過過載這個函式來定義處理訊息的方式。
總結
Android訊息機制共有三種訊息處理方式,它們是互斥的,優先順序從高到低分別是1.Runnable.run()
2.Handler.callback
3. 過載Handler.handleMessage()