post
系列經過查看源碼可知,post(Runnable r)
、postDelayed(Runnable r, long delayMillis)
最終調用的都是sendMessageDelayed
方法:java
// post public final boolean post(Runnable r){ return sendMessageDelayed(getPostMessage(r), 0); } // postDelayed public final boolean postDelayed(Runnable r, long delayMillis){ return sendMessageDelayed(getPostMessage(r), delayMillis); }
postAtTime
postAtTime(Runnable r, long uptimeMillis)
最終調用的是sendMessageAtTime
方法:segmentfault
// postAtTime public final boolean postAtTime(Runnable r, Object token, long uptimeMillis){ return sendMessageAtTime(getPostMessage(r, token), uptimeMillis); }
這裏面都有一個共同的方法getPostMessage
:ide
private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); m.callback = r; return m; }
m.callback = r
這句能夠看出:getPostMessage
就是把傳入的 Runnable 賦值給 Message 對象的 callback 屬性。函數
sendEmptyMessage
sendEmptyMessage
最終指向sendEmptyMessageDelayed
函數:oop
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); }
msg.what = what
這句能夠看出:sendEmptyMessageDelayed
就是把 what 賦值給 Message 的 what 屬性。post
sendMessage(msg : Message)
至於經常使用的sendMessage(msg : Message)
就不用細說了,這是直接傳入 Message 類型的參數。this
綜合以上這幾點來講,各類發送消息的方法最終都是把消息賦值給 Message 對象(或者 Message 的屬性),並且這些方法最終調用的都是 MessageQueue 中的
enqueueMessage
方法,就是把消息加入消息隊列
enqueueMessage
方法方法較長,咱們看看關鍵的幾行:spa
Message prev; for (;;) { prev = p; p = p.next; if (p == null || when < p.when) { break; } if (needWake && p.isAsynchronous()) { needWake = false; } } msg.next = p; // invariant: p == prev.next prev.next = msg;
用一個無限循環將消息加入到消息隊列中(鏈表的形式),到這裏把消息發出去並加入隊列這兩步算是完成了,接下來就是取出並處理消息。.net
Looper 中有一個死循環(Looper.loop()
)用來不斷從隊列中取出消息:線程
public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); ...代碼省略 msg.target.dispatchMessage(msg); ...代碼省略 msg.recycleUnchecked(); } }
queue.next()
每次取出一條 Message 消息,而後交由msg.targer.dispatchMessage(msg)
處理,從上篇文章中能夠知道,msg.targer
就是發出消息的 Handler,因此咱們只須要關注dispatchMessage(msg)
。
dispatchMessage(msg)
處理消息dispatchMessage(msg)
在 Handler 類中
public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
handleCallback
方法(message.callback.run())mCallback.handleMessage(msg)
handleMessage(msg)
方法第 1 點就是上面的 【1.1post
系列】 和 【1.2postAtTime
】,第 3 點就是咱們最多見的handleMessage
方法。須要注意一下就是callback.run()
這裏直接調用線程的 run 方法,至關於普通方法調用, 不會開啓新的線程。
如今談談第 2 點,Handler 有不少種構造方法,除了上一篇文章提到的public Handler(Looper looper)
和Handler()
等,還有一個:
public Handler(Looper looper, Callback callback) { this(looper, callback, false); }
Callback 是這樣的:
public interface Callback { public boolean handleMessage(Message msg); }
須要重寫handleMessage
,這不就是 Handler 裏面的handleMessage
嗎?其實二者是有區別的:
// Handler public void handleMessage(Message msg) {} // Callback public boolean handleMessage(Message msg);
Callback 裏面的handleMessage
返回值是 Boolean 類型的,那麼接下來分別返回 true 和 false 看看效果吧:
class MainActivity : AppCompatActivity() { var handler: Handler? = null var looper: Looper? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) looper = Looper.getMainLooper() val callback = object: Handler.Callback{ override fun handleMessage(msg: Message?): Boolean { Log.e("abc","--- Callback:threadName ---" + Thread.currentThread().name ) return true } } val thread = object : Thread() { override fun run() { super.run() handler = object : Handler(looper, callback) { override fun handleMessage(msg: Message?) { super.handleMessage(msg) Log.e("abc","--- handleMessage:threadName ---" + Thread.currentThread().name ) } } } } thread.start() myBtn.setOnClickListener { handler?.sendEmptyMessage(4) } } } // Log 打印狀況 --- Callback:threadName ---main
若是返回值類型改爲 false:
val callback = object: Handler.Callback{ override fun handleMessage(msg: Message?): Boolean { Log.e("abc", "--- Callback:threadName ---" + Thread.currentThread().name ) return false } } // Log 打印狀況 --- Callback:threadName ---main --- handleMessage:threadName ---main
因此,Callback 中的handleMessage
返回 true 就不繼續執行 Handler 中的handlerMessage
了,反之則兩個handleMessage
都執行。其實這些從dispatchMessage
方法中能夠看出來(返回 true 則 return 終止,不然繼續執行 handleMessage):
if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg);
上面主要講了消息的發送和取出,大概知道了 Handler 消息機制的工做流程:
post
(postDelayed
、postAtTime
)或者sendMessage
(sendEmptyMessage
)把消息(Message)交給 MessageQueueMessageQueue.enqueueMessage
方法將 Message 以鏈表的形式放入消息隊列中Looper.loop()
循環調用 MessageQueue 的next()
取出消息,交給 Handler 的dispatchMessage
方法處理消息dispatchMessage()
中分別判斷msg.callback
和構造函數傳入的mCallback
是否爲空,不爲空則執行它們的回調,爲空則執行 Handler 自身的handlerMessage
方法。下面這樣寫會有內存泄漏風險:
val mHandler = object : Handler() { override fun handleMessage(msg: Message?) { super.handleMessage(msg) } }
Android Studio 會標黃警告,鼠標放在 handler 代碼塊部分還會彈出提示,大概意思就是建議你用靜態模式或者弱引用。上面這種寫法至關於定義了一個匿名內部類,非靜態的匿名內部類默認是持有外部類(對應 Activity 等)引用的。若是發消息的 handler 所在線程還在執行,當前 Activity 就被 finish 了,那麼該 Handler 的匿名內部類持有 Activity 的引用,因此 Activity 對象是沒法被 GC 機制回收的。即:執行了 finish 代碼,但 Activity 對象還在內存中(內存泄漏)。這種對象若是愈來愈多,就會有 OOM(內存溢出)的可能。
kotlin 中沒有靜態類這個概念,這裏用 java 靜態內部類舉例:
static class MyHandler extends Handler { WeakReference<MyActivity> weakActivity; MyHandler(MyActivity activity) { weakActivity = new WeakReference<>(activity); } @Override public void handleMessage(Message msg) { super.handleMessage(msg); MyActivity activity = weakActivity.get(); // activity.text = "......" } }
- 靜態內部類不持有外部類引用,因此不會致使 Activity 對象泄漏(java 中 「靜態的」等於「類的」,靜態內部類若是能持有外部類引用,那說明外部類的引用就是內部「類的」,這不符合邏輯,這樣寫編譯都不經過)。
- 但該靜態內部類必須使用外部類的引用(好比操做 UI),此時就能夠用弱引用的方式。上面代碼用的是把 Activity 的弱引用在 Handler 構造函數中初始化,這樣若是須要操做 UI,可使用
activity.text = "test"
這種方式。
參考文章: