咱們平時在開發中,常常用到Handler,用來發送消息,處理消息。 或者作一些延遲發送消息,跨線程發消息,或者更新UI,或者去實現一些定時輪詢的操做。 安卓發展至今,已經有不少框架,能夠代替這樣原生Handler的通訊方式。 好比Eventbus, Rxjava,AyncTask...等等。可是實際上底層依然是對Handler的封裝。那麼Handler到底是什麼?java
簡而言之:面試
Handler就是Android系統提供給咱們,用來更新UI的一套機制,也是一套消息處理機制。經過Handler,能夠用來發送消息,處理消息。若是不遵循這樣的機制,就沒有辦法更新UI,會拋出異常。框架
1.Handler: 消息的發送和處理者async
2.Message: 消息ide
3.MessageQueue: 消息存放的隊列oop
4.Looper : 從消息隊列裏面一條一條取消息的消息偵聽器,或者消息泵post
5.線程: 當前是在哪一個線程學習
也許不少人在網上都看過不少資料去解釋這樣一個消息機制,可是若是向別人闡述這樣一個原理的時候,或者面試的時候,我相信不少人仍是模棱兩可,弄不太清楚。 那麼,經過一個簡單的生活案例,來幫助理解一下:ui
eg: 咱們都知道讀書的時候,咱們常常須要向老師請假之類。this
好比:報告老師,我要上洗手間。而後老師說:容許,快去吧。
過了一會。
又給老師報告:報告老師,後面有同窗踢我凳子。老師說:你先坐前面來,不要理他。
固然,這只是比喻。咱們經過這個比喻,來比較生動形象的去理解handler就容易多了。
1.handler:學生。
2.message:報告老師的內容
3.Looper :老師本身
4.messagequeue: 老師的耳朵和聽力記憶
解釋:
* 學生(handler)向老師(Looper)舉手
* 說 「我要上洗手間」這個報告(message),
* 而後老師的耳朵(messagequeue)聽到了這個報告,
* 先是反饋了學生的請求(dispatchHandle),告訴這個同窗,贊成他的請求,
* 因而學生本身就上洗手間去了(handleMessage)
ps: 老師: 在這個過程當中,就是一個消息的接受者,源源不斷的接受學生的各類報告或者消息,存在老師的記憶裏, 老師又沒有分身術,只有一張嘴,因此同一時間,只能根據記憶中的消息,一條一條的反饋給學生,處理他們的請求。 學生: 在這個過程當中,咱們能夠發現,學生既是消息的發出者,又是消息的處理者。 收到老師的贊成後,因而就高高興興的去上洗手間去了。
整個過程如圖:
由圖能夠看出:
1.handler負責發送消息,接收處理消息
2.Looper負責接收handler發過來的消息
3.MessageQueue就作爲Looper消息泵內部的消息容器 3.Looper在內部,將發送過來的消息,交給自身的消息隊列,並按時間順序加入其中 4.Looper在內部,經過不斷循環的方式,將消息從隊列中一個一個取出,回傳給handler
此時你有可能會問:那麼Handler它怎麼知道應該往哪發消息,而且發給哪一個Looper,加入這個Looper的消息隊列呢?答案在構造方法中。
Handler的建立,調用Handler的構造方法便可。 new Handler(). 那麼咱們看下Handler的構造方法都作了些什麼呢?Handler的構造方法有好幾個,咱們先從空構造看起:
//從這開始看起,空構造 public Handler() { this(null, false); } public Handler(Callback callback) { this(callback, false); } public Handler(Looper looper) { this(looper, null, false); } public Handler(Looper looper, Callback callback) { this(looper, callback, false); } public Handler(boolean async) { this(null, async); } //而後看到這個構造方法 public Handler(Callback callback, boolean async) { if (FIND\_POTENTIAL\_LEAKS) { final Class<? extends Handler> klass = getClass(); if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) && (klass.getModifiers() & Modifier.STATIC) == 0) { Log.w(TAG, "The following Handler class should be static or leaks might occur: " + klass.getCanonicalName()); } } //構造方法內部,有一個默認的looper對象,而且這個對象是經過myLooper獲得,也就是當前線程的looper。 //當前線程:默認狀況就是主線程,爲何會是主線程,後面會講 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; } public Handler(Looper looper, Callback callback, boolean async) { mLooper = looper; mQueue = looper.mQueue; mCallback = callback; mAsynchronous = async; }
上面代碼能夠看出,在handler的默認構造器中,有一句:mLooper=Looper.myLooper(). 這說明Handler 默認的時候,有一個Looper對象。可是這個Looper對象是怎麼建立得來的呢?點擊去發現:就是根據當前線程返回一個looper對象。當前線程是什麼呢?默認狀況下,就是主線程,也就是MainLooper.
/** \* Return the Looper object associated with the current thread. Returns \* null if the calling thread is not associated with a Looper. */ //解釋一下:根據當前線程,返回looper對象。若是線程沒有與之關聯的Looper,那麼返回空 public static @Nullable Looper myLooper() { return sThreadLocal.get(); }
好了,看到這裏,咱們就看到了Handler和一個默認looper對象如何關聯的。至於looper對象的如何建立,後面再詳細講解。
咱們能夠得出結論:
* 默認狀況下:new Handler()中的looper對象是主線程的looper對象 ,那麼消息就是發給主線程的handler進行處理。
* 須要和特定線程的Handler通訊,咱們就須要調用new Handler(Looper looper) ,傳入特定線程的Looper對象便可。
* Looper對象是屬於什麼線程,那麼handler,就是往哪一個線程進行發送消息和處理消息。
搞清楚Handler和Looper如何進行關聯的關係之後,咱們從消息的發送開始理解。
Handler 如何發送消息,消息從哪裏產生? 要搞清楚消息的產生,咱們首先要知道handler發送一條空消息是sendEmptyMessage().那麼咱們就跟蹤這個方法: 方法的參數what ,就是一個標記位,先無論它。
/** public final boolean sendEmptyMessage(int what) { return sendEmptyMessageDelayed(what, 0); }
再繼續往下跟蹤
//這裏能夠看到,sendEmptyMessage()默認會調用sendEmptyMessageDelayed()方法 public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { //內部,經過Message.obtain(),產生了一條消息Message Message msg = Message.obtain(); msg.what = what; //而後再調用sendMessageDelayed()方法 return sendMessageDelayed(msg, delayMillis); }
public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis); }
這裏能夠看到發送空消息時,Message是在方法內部,經過Message.obtain產生的。 而且會層層調用,最終是這麼一個方法路徑:
sendEmptyMessage-->sendMessageDelay-->sendMessageAtTime ,最終都是調用sendMessageAtTime()來發送消息的。
經過上面sendMessageAtTime()發送消息,消息產生後,按照前面的圖的理解,它是會發送出一個Messgae,而且發給Looper,由Looper加入到消息隊列的。那麼代碼上是怎樣的呢?
public boolean sendMessageAtTime(Message msg, long uptimeMillis) { //1.首先獲取到queue對象, MessageQueue queue = mQueue; if (queue == null) { RuntimeException e = new RuntimeException( this + " sendMessageAtTime() called with no mQueue"); Log.w("Looper", e.getMessage(), e); return false; } //2\\. 將消息,插入到這個消息queue隊列中去,而且附帶了一個時間值 return enqueueMessage(queue, msg, uptimeMillis); }
咱們能夠看出:
在最終發送消息的地方,拿到了Queue隊列對象,而後就把消息加入到了這個Queue隊列中去了。 這個Queue對象的獲取,咱們能夠觀察handler的構造看到:每一次Handler建立的時候,會拿到looper對象,再經過looper對象來獲取到內部的這個Queue隊列對象。回顧handler的建立可發現,以下:
public Handler(Callback callback, boolean async) { .... .... //1先拿到線程的looper mLooper = Looper.myLooper(); if (mLooper == null) { throw new RuntimeException( "Can't create handler inside thread that has not called Looper.prepare()"); } //2經過looper獲取到消息queue隊列 mQueue = mLooper.mQueue; mCallback = callback; mAsynchronous = async; }
再看下消息加入queue隊列的過程
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { //這裏能夠發現 消息msg的target屬性:是this,也就是handler 自身當前對象 msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
在加入隊列的時候,能夠看到消息msg的地址,也就是處理者target(由誰來最終處理消息),賦值爲this。
這也就說明了,handler默認狀況下,發送消息的是它本身,處理消息的也是它本身。
總結一下上面消息的發送過程:
* 發送出去 sendEmptyMessage(),消息的產生在這個裏面
* 調用sendEmptyMessageDelay()
* 內部調用sendMessageDelay()
* 內部調用sendMessageAtTime()
* 內部經過當前線程,首先獲取到mQueue對象,也就是 消息隊列對象MessageQueue
* 當queue不爲空的狀況下,設置 target,發送給誰, 默認是this --handler本身
* 而後把消息message,放到消息隊列中。queue.enqueueMessage(消息,時間);
####7. 偵聽消息和取消息的過程
咱們知道,消息發送到Looper中後,就進入到了隊列中,而後等待Looper的循環取出進行分發。那麼Looper.loop() 這個循環的過程是在何時觸發的呢?因爲Android默認的線程是主線程,因此在應用進程啓動以後,就會進入ActivityThread這個主線程中,而在這個ActivityThread中的main()方法,就會觸發Looper.loop()開始偵聽主線程的消息。
//main方法
public static void main(String[] args) {
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//1. 觸發loop
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
能夠看到,在主線程的ActivityThread main()方法內部,觸發Looper.loop()。學過java的人都知道,main方法是一個類的主入口.
那麼loop是如何進行取消息的呢?點進去繼續往下看
public static void loop() { // 1.拿到當前線程looper對象 final Looper me = myLooper(); if (me == null) { throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread."); } 2\. 獲得 looper對象內部的消息隊列queue final MessageQueue queue = me.mQueue; ... ... //3.死循環,配合隊列進行取消息 for (;;) { //4.取出一條消息 Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } // This must be in a local variable, in case a UI event sets the logger final Printer logging = me.mLogging; if (logging != null) { logging.println(">>>>> Dispatching to " + msg.target + " " + msg.callback + ": " + msg.what); } final long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs; final long traceTag = me.mTraceTag; if (traceTag != 0 && Trace.isTagEnabled(traceTag)) { Trace.traceBegin(traceTag, msg.target.getTraceName(msg)); } final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); final long end; try { //4.分發消息 msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } } } }
能夠看到:
Looper.loop()方法中
2.經過myLooper,拿到一個Looper對象
3.取出looper中的消息隊列 mQueue
4.而後經過一個死循環,裏面經過mQueue.next來取消息
若是消息爲空了,就return掉,
5.若是消息不爲空, 就會調用
msg.target.dispatchMessage(消息)。將消息發出去
msg.target:就是handler本身
handler.dispatchMessage(消息)方法,將消息回調到dispatch中去
經過上面Looper取消息的過程。咱們看到了。消息在最終取出後,會經過 dispatchMsg進行回傳,交給處理者。 這個處理者,被賦值在Msg.target中. Msg的target本質上就是handler。
在前面發送消息,將消息加入隊列的時候,咱們看到過,msg.target=this,是在那個時候將消息的處理者進行了賦值。
因此這裏,當取出消息後,就又經過handler,經過它的dispatchMessage(msg)進行回傳的。
} final long start = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); final long end; try { //消息分發,回傳給處理者 。也就是handler本身。 msg.target.dispatchMessage(msg); end = (slowDispatchThresholdMs == 0) ? 0 : SystemClock.uptimeMillis(); } finally { if (traceTag != 0) { Trace.traceEnd(traceTag); } }
繼續往下跟蹤能夠發現:
/** \* Handle system messages here. */ public void dispatchMessage(Message msg) { //若是消息的callback 處理者不爲空,就經過這個callback進行處理。這個callback是什麼呢? 後續再講解 if (msg.callback != null) { handleCallback(msg); } else { //默認狀況下,走這個分支 if (mCallback != null) { //若是全局的callback不爲空,就會執行這裏,再也不執行handlemessgae if (mCallback.handleMessage(msg)) { return; } } // 回傳給消息處理者,處理消息, handleMessage(msg); } }
分發消息後,默認會進入第二個分支。一般狀況下callback是沒有進行設置,因此直接就會回調handleMessage(msg).走完整個流程.進入處理消息流程
但是這個msg.callback是什麼呢? 還有全局的mCallback又是什麼呢? 分發消息的時候,若是這些不爲空。又會觸發什麼呢?繼續日後看
因爲咱們知道通知UI刷新的機制有4種方式:
view.post(runnable) handler.post(runnable) runOnUiThread(runnable) handler.sendMsg(runnable)
咱們跟蹤一下view.post(runnable).進入view源碼:
//傳入一個runnable public boolean post(Runnable action) { final AttachInfo attachInfo = mAttachInfo; if (attachInfo != null) { //而後將runnable,交給handler的post執行 return attachInfo.mHandler.post(action); } // Postpone the runnable until we know on which thread it needs to run. // Assume that the runnable will be successfully placed after attach. getRunQueue().post(action); return true; }
而後進入到handler的內部中post
public final boolean post(Runnable r) { return sendMessageDelayed(getPostMessage(r), 0); } 複製代碼能夠看到runnable,被包裝進入到了發送消息的getPostMessage(r)方法中。跟進去: private static Message getPostMessage(Runnable r) { Message m = Message.obtain(); //看到沒!!! callback,原來就是指 咱們使用view.post(runnbale)的這個對象 //這個runnable,會賦值給msg.callback。 //因此當咱們使用別的方式進行更新UI或者消息通訊的時候,在handleMessage前,就會進入callback不爲空的判斷 m.callback = r; return m; }
也就是這裏msg.callback: 再貼一遍代碼
/** \* Handle system messages here. */ public void dispatchMessage(Message msg) { //若是消息的callback 處理者不爲空,就經過這個callback進行處理。這裏就是使用別的方式進行更新UI或者消息的時候,進入這裏處理,再也不進入handleMessage if (msg.callback != null) { handleCallback(msg); } else { //默認狀況下,走這個分支 if (mCallback != null) { //若是全局的callback不爲空,就會執行這裏,再也不執行handlemessgae if (mCallback.handleMessage(msg)) { return; } } // 回傳給消息處理者,處理消息, handleMessage(msg); } }
而mCallback 則是咱們初始化構造handler的時候,傳入的callback,進行攔截消息處理使用。
咱們能夠發現,最終都是進入到了handler的post方法中,經過handler機制來實現。
未完待續....
繼續講解更深刻的細節...
這裏發現有一個sThreadLocal對象,咱們的looper對象就是從這個對象中獲取的。這個ThreadLocal對象,其實就是一個與線程相關的對象,保存了線程的相關變量,狀態等等。再繼續往下看:發現最終就是從這個線程相關的對象中,內部有一個map對象,從裏面獲取得來。這個地方只是一個單純的get
public T get() { Thread t = Thread.currentThread(); 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(); }
這個地方依然不是咱們想要的答案,咱們想看的是Looper對象是在哪裏建立的。
今年金九銀十我花一個月的時間收錄整理了一套知識體系,若是有想法深刻的系統化的去學習的,能夠點擊傳送門,我會把我收錄整理的資料都送給你們,幫助你們更快的進階。