寫在前面的話
簡書支持Markdown語法,從這篇文章開始,后面的文章都會改成Markdown編輯,讓我們一起來學著使用Markdown吧。:)
在前面兩篇文章中
中我們介紹了Hanlder的構造方法與Looper的初始化。本篇中我們將對剩余部分進行剩余部分的分析。
主線程的Looper初始化
主線程的looper的初始化是在Looper.prepareMainLooper中進行初始化的。而這個方法被調用位置在ActivityThread中main方法中其代碼引用如下:
Looper.prepareMainLopper(); ActivityThread thread = new ActivityThread(); thread.attach(false); if (false) { Looper.myLooper().setMessag } Looper.loop();
而ActivityThread的main方法是Android應用程序主線程的入口,所以我們可以理解為:主線程的Looper在應用啟動時已經初始化過了。
Handler的消息發送
我們在創建好Handler后,使用Handler發送消息一般調用根據其方法調用有:
sendMessage()
sendEmptyMessage()
sendMessageAtTime()
sendMessageDelayed()
其中主要區別在于如下源碼展示:
public final boolean sendMessage(Message msg) { return sendMessageDelayed(msg, 0); }
public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); }
public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); }
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } return enqueueMessage(queue, msg, uptimeMillis); }
可以看到,當發送EmptyMessage時,會在Handler中使用Message.obtain()來構造一個Message,而如果發送無延時消息時,會設置延時時間為0,最后會發送都會調用sendMessageAtTime()方法。所有的消息都會通過enqueMessage發送出去。
注意:Hanlder中的enqueMessage中會調用其中messageQueue.enqueMessage(msg, uptimeMillis),但是Handler中的MessageQueue對象是從Looper中get到的,所以,MessageQueue耦合的還是Looper
MessageQueue的消息遍歷
if (p == null || when == 0 || when < p.when) { // New head, wake up the event queue if blocked. msg.next = p; mMessages = msg; needWake = mBlocked; } else { // Inserted within the middle of the queue. Usually we don't have to wake // up the event queue unless there is a barrier at the head of the queue // and the message is the earliest asynchronous message in the queue. needWake = mBlocked && p.target == null && msg.isAsynchronous(); 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; } if (needWake) { nativeWake(mPtr); }
如上圖中代碼中所示:其中主要操作是將新加入的Message與當前的MessageQueue中的頭進行比較,如果當前有新消息進入并且觸發時間為0或小于當前頭節點的時間,如果隊列阻塞,則喚醒線程處理。如果新消息觸發時間長于隊列中的消息時間,則按時間排序,插入到隊列中。如果喚醒線程,則調用nativeWake函數進行JNI方法調用發送消息。
消息循環處理與回調
Looper中的loop()方法會拿到與looper耦合的MessageQueue對象,由MessageQueue調用next()方法,如果meesage對象不為空,則調用msg.target.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); } }
其中,else語句中的handlerMessage最終會回調回當時創建的Handler對應的handMessage方法中。
在回調中,我們注意到除了handleMessage的回調,還有可以注冊message的CallBack或者Handler的callback來回調。message的Callback需要在message創建時傳入一個Runnable對象。而Handler的Callback與handleMessage方法就目前而言使用上沒感覺有什么區別。
希望有了解的同學能對這個問題留言說明下,謝謝~!
寫到最后
Handler的基礎分析就算完成了,后續有時間會做其他相關的源碼分析。
不足之處,請大家批評指導。
ps:Markdown代碼框標記不怎么好用,大家有什么建議也可以留言(⊙o⊙)哦!