Handler是爲了解決非UI線程中UI更新的問題,這裏會產生一個疑問。爲啥要在UI線程中更新,通常都知道會產生卡頓問題。html
上張官方關係類圖,壓壓驚:
能夠看到他有四個子類,前面兩個是與異步數據庫操做相關的(contentProvider),後面兩個是與網絡請求(一個是處理http受權,另外一個是處理SSL錯誤請求)android
MessageQueue與Message,Looper,Handler數據庫
Handler 主要功能是發送消息和處理接受消息。通常經常使用的 handler.sendEmptyMessage(int what)
和 sendMessage(Message msg)
方法,下面就從 sendEmptyMessage(int what)
方法看看它是怎麼運做的?緩存
sendEmptyMessage 內部調用關係以下:網絡
sendEmptyMessage => sendEmptyMessageDelayed => sendMessageDelayed => enqueueMessageapp
public final boolean sendEmptyMessageDelayed(int what, long delayMillis) { //構造新的消息 使用sPool全局池保存回收的消息鏈表進行空消息緩存 Message msg = Message.obtain(); msg.what = what; return sendMessageDelayed(msg, delayMillis); } ... public final boolean sendMessageDelayed(Message msg, long delayMillis) { if (delayMillis < 0) { delayMillis = 0; } return sendMessageAtTime(msg, SystemClock.uptimeMillis() + 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); } ... private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) { msg.target = this; if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
uptimeMillis
沒有被用到,那他是用來幹什麼的?(uptimeMillis
是開機到如今的毫秒數,內部實現是一個native方法 )msg.setAsynchronous
怎麼使用其值?看了obtain方法後發現,sPool默認是static,因此屬於Message類,共享的,沒有初始化,那它何時進行賦值。答案就在recycle方法,顧名思義其實做用至關於回收那些沒用的消息,那這個是怎麼工做的?異步
... //recycle內部調用的recycleUnchecked函數 void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = -1; when = 0; target = null; callback = null; data = null; //關鍵代碼,其實能夠回收的話至關於把消息放到單鏈表的表頭 synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
能夠本身紙上畫下,下面看圖說話:
ide
private static final Object sPoolSync = new Object(); private static Message sPool; private static int sPoolSize = 0; private static final int MAX_POOL_SIZE = 50; ... public static Message obtain() { synchronized (sPoolSync) { if (sPool != null) { Message m = sPool; sPool = m.next; m.next = null; m.flags = 0; // clear in-use flag sPoolSize--; return m; } } return new Message(); }
直接上圖:
函數
歸納:MessageQueue中使用一個單鏈表來維護消息隊列。經過Looper對象分發消息,可是不能直接把Message入隊,須要經過Looper關聯的Handler來發送消息。oop
關鍵看兩個方法:enqueueMessage 與 next(後續分析) 方法,前面一個是消息入隊,後面一個是消息出隊。
先來看看 enqueueMessage
方法,首先它有兩個參數:消息--msg 和觸發時間--when,簡單來講,若是p爲空的話直接賦值 mMessages = msg
,若是p不爲空的話則須要根據觸發時間--when插入到鏈表合適的位置。
boolean enqueueMessage(Message msg, long when) { ... synchronized (this) { ... //消息被標記使用 msg.markInUse(); msg.when = when; Message p = mMessages; boolean needWake; 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 { ... //關鍵代碼 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; } // We can assume mPtr != 0 because mQuitting is false. if (needWake) { nativeWake(mPtr); } } return true; }
Looper的構造函數修飾符是private的,那麼他是在哪裏被實例化?經過搜索,發現 prepare()
和 prepareMainLooper()
兩個方法。
prepare()
方法官方說明;
做爲looper初始化當前線程。提供一個機會來建立handler並使用looper。在使用以前,請在此方法以後調用loop(),並在結束時調用quit()
prepareMainLooper()
方法官方說明;
做爲looper初始化當前線程,並標記其爲application主線程的looper。在application主線程中的looper被Android系統建立,所以開發者請永遠不要手動調用這個方法。
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 void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed)); }
看上面的prepareMainLooper()
代碼,發現作了兩個事: prepare(false)
和 myLooper()
。
prepare(false)
方法中的sThreadLocal字段的類型是 ThreadLocal
,用來幹什麼呢?實現一個線程本地存儲,一個讓每一個線程都有擁有value的變量。另外,能夠看看構造函數Looper幹了些什麼事情?private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread(); }
對於myLooper()
來講,prepare()中提到了會將looper放到線程存儲ThreadLocal中,此處只須要從中取出並返回便可,所以代碼只有一行return sThreadLocal.get();
疑問
在activity當中實例的Handler,咱們並無調用loop方法?
查看prepareMainLooper()調用者能夠看到,在SystemServer.run()與ActivityThread.main()中都在調用Looper.prepareMainLooper()後不遠就調用了Looper.loop()。而這兩處能夠推斷一個是系統應用的主線程,一個是用戶應用的主線程,然後面這個就是答案。
public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // might block if (msg == null) { return; } msg.target.dispatchMessage(msg); msg.recycleUnchecked(); } }
這裏就一目瞭然了:一個死循環,不斷從隊列中取消息並分發,若是取到null就說明消息隊列已經退出或被釋放,此時loop終止。msg.target.dispatchMessage(msg)中target即是在發送消息的handler對象,dispatchMessage()即是對消息的處理了。