Handler源碼解析

Handler使用主要做用一句話歸納: 線程間通訊

在平常開發中主要做用於兩方面:
一、在UI線程進行耗時操做時,將耗時操做拋到子線程進行處理,不然容易ANR。
二、在子線程中刷新UI。
java

1、Handler簡介

HandlerLooperMessageQueueMessage 是組成Handler通訊機制的基礎。android

1.1Handler簡單使用

Handler的使用基本如如下代碼所示,或者繼承Handler重寫handleMessage,處理不一樣what標識的Message。不是本文討論的重點,不作過多敘述。設計模式

//建立子線程Handler
HandlerThread mHandlerThread = new HandlerThread("daqi");
mHandlerThread.start();
Handler mHandler = new Handler(mHandlerThread.getLooper());
//建立Message
Message message = mHandler.obtainMessage();
//發送Message
mHandler.sendMessage(message);
//post
mHandler.post(new Runnable() {
    @Override
    public void run() {

    }
});
複製代碼

1.2Handler工做流程

建立Handler,並綁定Looper -> Handler發送Message -> Message存儲到Looper的MessageQueue中 -> Looper在MessageQueue中拿取頂部Message -> 將Message發送給目標Handlerbash

Handler、Looper、MessageQueue 和 Message的關係:
異步

  • 一個線程只能有一個Looper;
  • 一個Handler只能綁定一個Looper;
  • 多個Handler能夠綁定同一個Looper;
  • 一個Looper管理着一個MessageQueue。
  • MssageQueue做爲Message「收信箱」,收納着Handler發送的Message。

2、提出問題

帶着問題看源碼:
一、Looper如何確保線程中只有一個單例。
async

二、爲何建議使用Handler#obtainMessage()獲取Message對象,而不是直接new。
ide

三、Handler的sendMessage() 和 post()有什麼區別。
函數

四、Looper如何管理Message隊列(即前後發送不一樣延遲時間的Message,Message隊列如何排序)。
oop

五、removeCallbacks、removeMessages 和 removeCallbacksAndMessages都移除了什麼。
源碼分析

3、源碼分析

3.一、Looper機制

Handler在建立時,默認構造方法會綁定當前線程。因此咱們選擇先從Handler的默認構造方法看起。

#Handler.java
//無參構造函數
public Handler() {
   this(null, false);
}

public Handler(Callback callback, boolean async) {
    //....

    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
            + " that has not called Looper.prepare()");
    }
     mQueue = mLooper.mQueue;
     mCallback = callback;
}
複製代碼

  建立Handler對象時,無參構造函數會獲取當前線程的Looper並獲取到其MessageQueue存儲到Handler自身變量中。

但咱們也觀察到,若是沒有Looper的Thread中建立,會拋出RuntimeException,並告訴你該線程無Looper。

從Handler的默認構造方法中得知,在建立Handler前,須要先在當前線程中建立Looper對象和MessageQueue對象。而建立Looper對象和MessageQueue對象只須要調用以下方法:

Looper.prepare();
Looper.loop();
複製代碼

 prepare的意思是準備,便可以猜想Looper是在Looper#prepare()中初始化的,因此先從Looper#prepare()的源碼看起:

#Looper.java
//主要用於做爲存儲的Looper實例的key。
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

private Looper(boolean quitAllowed) {
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}

public static void prepare() {
    prepare(true);
}

private static void prepare(boolean quitAllowed) {
    //ThreadLocal#get()獲取當前線程的looper對象
    if (sThreadLocal.get() != null) {
        //若是Looper已經實例化完,則會拋出異常
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    //若是以前當前線程沒有初始化過Looper,則建立Looper並添加到sThreadLocal中
    sThreadLocal.set(new Looper(quitAllowed));
}
複製代碼

 咱們發現Looper#prepare()調用重載函數Looper#prepare(boolean)。在這方法中,Looper會被初始化。查看Looper私有構造函數,發現Looper會初始化MessageQueue並存儲當前線程。

而Looper被初始化是有一個前提的,即sThreadLocal.get() == null。不然會拋出RuntimeException,並告訴你該線程只能建立一個Looper對象。

sThreadLocal是Looper類中定義的一個靜態ThreadLocal常量。繼續查看ThreadLocal#get()和ThreadLocal#set()方法。

#ThreadLocal.java

public T get() {
	//獲取當前線程	
    Thread t = Thread.currentThread();
    //線程中存在一個ThreadLocal.ThreadLocalMap類型的變量
    //根據當前線程thread獲取到對應的ThreadLocal.ThreadLocalMap變量。
    ThreadLocalMap map = getMap(t);
    if (map != null) {
    	//this表示Looper類中的靜態ThreadLocal常量sThreadLocal
        //由於sThreadLocal是靜態常量,做爲「key」,確保變量爲單例。
        //根據sThreadLocal獲取到對應的ThreadLocalMap.Entry值。
        ThreadLocalMap.Entry e = mapgetEntry(this);
        if (e != null) {
        	//從ThreadLocalMap.Entry中獲取到對應的Looper,
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

public void set(T value) {
    //獲取當前線程	
    Thread t = Thread.currentThread();
    //線程中存在一個ThreadLocal.ThreadLocalMap類型的變量
    //根據當前線程thread獲取到對應的ThreadLocal.ThreadLocalMap變量。
    ThreadLocalMap map = getMap(t);
    if (map != null)
    	//將sThreadLocal做爲「key」,Looper實例做爲「value」存儲到ThreadLocal.ThreadLocalMap中
        map.set(this, value);
    else
    	//建立Map並存儲值
        createMap(t, value);
}

void createMap(Thread t, T firstValue) {
	//建立ThreadLocalMap,構造方法中傳入第一次存儲的鍵值對,並賦值到當前線程的threadLocals變量中。
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
複製代碼

 能夠觀察到,get()和set()方法獲取當前線程中的ThreadLocal.ThreadLocalMap變量。再將Looper#sThreadLocal做爲key,存儲或獲取對應的value,而value就是當前線程建立的Looper實例。

get()時是根據當前線程獲取的Looper單例,再結合Looper#prepare(boolean),能夠知道單個線程只會生成Looper單個實例。

問題1:Looper如何確保線程中只有一個單例。

回答:將Looper構造方法私有化。經過Looper的靜態方法,確保只建立一次Looper對象,再將靜態常量sThreadLocal做爲key,Looper對象做爲value,存儲到當前線程的ThreadLocal.ThreadLocalMap變量中。

查看完Looper初始化的流程,再看看Looper#loop()的源碼


#Looper.java

public static void loop() {
	//獲取當前線程的Looper
    final Looper me = myLooper();
    //若是Looper沒有初始化,則拋異常
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    //從Looper實例中獲取當前線程的MessageQueue
    final MessageQueue queue = me.mQueue;
    
	//消息循環(經過for循環)
    for (;;) {
    	//一、從消息隊列中獲取消息
        Message msg = queue.next(); 
        if (msg == null) {
            //沒有消息代表消息隊列正在退出。
            return;
        }
		
        //省略代碼.....
        //二、將Message發送給其標記的targetHandler
        msg.target.dispatchMessage(msg);
           
        //省略代碼.....
      	
        //三、回收可繼續使用的Message
        msg.recycleUnchecked();
    }
}
複製代碼

Looper#loop()主要作3件事:

一、不斷從MessageQueue中取出Message,若暫無Message,則無限等待。
二、將Message發送給目標Handler進行處理
三、回收Message對象

但發現有一種狀況,當next獲取到的Message爲空時,則會退出Looper#loop()方法,即意味着消息循環結束。那何時MessageQueue#next()返回null?

#MessageQueue.java
Message next() {
    //若是消息循環已經退出並處理掉,請返回此處。
    //若是應用程序嘗試在退出後從新啓動looper,則可能會發生這種狀況。
    //即MessageQueue調用了quit()方法,再次調用Looper#looper()方法時。
    final long ptr = mPtr;
    if (ptr == 0) {
        return null;
    }

    //決定消息隊列中消息出隊的等待時間 or 標記爲無限等待狀態
    int nextPollTimeoutMillis = 0;
    for (;;) {
    	//.....
    	
        // nativePollOnce方法在native層方法。
        //如果nextPollTimeoutMillis爲-1,則無限等待,此時消息隊列處於等待狀態。
        //如果nextPollTimeoutMillis爲0,則無需等待當即返回。
        //若nextPollTimeoutMillis>0,最長阻塞nextPollTimeoutMillis毫秒(超時),若是期間有程序喚醒會當即返回。
        nativePollOnce(ptr, nextPollTimeoutMillis);
		
        //嘗試檢索下一條消息。 若是找到則返回。
        synchronized (this) {
        	//獲取從開機到如今的毫秒數
            final long now = SystemClock.uptimeMillis();
            Message prevMsg = null;
            //獲取MessageQueue中的頂層Message
            Message msg = mMessages;
            
            //.....
            if (msg != null) {
            	//若是massage的時間大於當前時間
                //Message的when = Handler發送Message1時的開機時間SystemClock.uptimeMillis() + Message自身的延遲時間
                if (now < msg.when) {
                    // 下一條消息還沒有就緒。 設置該Message的等待時間以在準備就緒時喚醒。
                    //將msg.when - now(當前開機時間) 獲得該Message須要多久以後發送。
                    //則刷新nextPollTimeoutMillis的值,設置等待時間。
                    nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                } else {//不然立刻發送Message
                
					//只有當msg.target == null時,prevMsg纔會賦值。
                    //聽從Handler#obtainMessage()則通常不爲空,此狀況不考慮。
                    if (prevMsg != null) {
                        prevMsg.next = msg.next;
                    } else {
                    	//剛開始時prevMsg爲空
                        //則mMessages(頂層Message)指向當前頂層Message的下一個Message
                        mMessages = msg.next;
                    }
                    //將返回的Message的下一個Message引用置空。
                    msg.next = null;
                    msg.markInUse();
                    return msg;
                }
            } else {
                //若是MessageQueue中沒有Message,則會將nextPollTimeoutMillis重置爲-1,繼續等待
                nextPollTimeoutMillis = -1;
            }

            //.....
        }

        //.....
    }
}
複製代碼

  從源碼開頭得知,當MessageQueue退出時,MessageQueue#next()則會返回Message對象爲空,從而關閉消息循環。

MessageQueue#next()主要進行等待操做返回Message操做。而等待操做分兩種狀況:

一、MessageQueue隊列中無Message,則進行無限等待操做。

二、當Message還沒處處理時間時,則計算該Message還須要等待的時間,進行相應時間的延遲。

查看Handler如何處理Message:

#Handler.java
public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        //若是Message的callback不爲空,則將消息交由Message的callback處理
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //若是Handler的callback不爲空,則將消息交由Handler的callback處理
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //最後才交由Handler的handleMessage()方法處理。
        handleMessage(msg);
    }
}
複製代碼

     Handler#dispatchMessage()主要做用時將Message分發處理。

當該Message對象的callback爲空,目標Handler的callback也爲空時,才輪到handleMessage()進行消息處理。

3.二、Message的循環再用機制

建立Message對象時,咱們通常會調用Handler#obtainMessage()獲取Message對象,而不是直接new。先從Handler#obtainMessage()開始查看起因:

#Handler.java
public final Message obtainMessage(){
    return Message.obtain(this);
}
複製代碼複製代碼
#Message.java
//Message鏈表,sPool是表頭
private static Message sPool;
//記錄當前鏈表中的數量
private static int sPoolSize = 0;

public static Message obtain(Handler h) {
    Message m = obtain();
    m.target = h;
    return m;
}

public static Message obtain() {
    //加鎖
    synchronized (sPoolSync) {
        if (sPool != null) {
            Message m = sPool;
            //鏈表表頭指向其下一個對象,即將表頭從鏈表中取出
            sPool = m.next;
            //重置返回的Message的一些信息
            m.next = null;
            m.flags = 0; // clear in-use flag
            //鏈表數量減一
            sPoolSize--;
            return m;
        }
    }
    //若是鏈表表頭爲空,則new Message對象。
    return new Message();
}
複製代碼複製代碼

Message#obtain(Handler)調用了重載方法Message#obtain()獲取到Message對象並將Message的目標設置爲調用Handler#obtainMessage()的Message。

Message對象中擁有一個Message類型的next對象,可經過next屬性連成一個Message鏈表。Message中維繫着一個靜態Message鏈表,當鏈表不爲空時,取出表頭的Message進行返回,不然new一個Message對象。

以前查看Looper#loop()源碼時獲知,Looper#loop()最後會調用Message#recycleUnchecked(),將Message進行回收。

#Message.java
//Message鏈表最大存儲數量值
private static final int MAX_POOL_SIZE = 50;

void recycleUnchecked() {
	//將消息保留在循環對象池中時將其標記爲正在使用。
    //清除全部其餘細節。
    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表明的是該須要回收的Message自身的next對象
            //將自身的next指向原表頭,
            next = sPool;
            //自身替換爲表頭,則經過表頭的加減實現該Message鏈表的增長和刪除。
            sPool = this;
            //鏈表存儲數量加一
            sPoolSize++;
        }
    }
}
複製代碼複製代碼

Message#recycleUnchecked()將Message的參數重置,並判斷當前Messag鏈表存儲的數量是否小於最大存儲值,若小於最大存儲值,則將該Message存儲到鏈表中,重複使用。
Message經過對鏈表表頭的增刪操做來進行鏈表的增減。

問題2:爲何建議使用Handler#obtainMessage()獲取Message對象,而不是直接new。

回答:Message的回收機制實際上是享元設計模式的實現,Message對象存在須要反覆、較大規模建立的狀況,使用享元設計模式能夠減小建立對象的數量,以減小內存佔用和提升性能。

總結

  • Message對象中擁有一個Message類型的next對象,可經過next屬性連成一個Message鏈表。

  • Message類中維繫着個靜態Message鏈表,並標記其存儲的數量值。

  • 調用Handler#obtainMessage()或Message#obtain()方法時,嘗試從該靜態鏈表中獲取循環再用的Message對象,不然new Message對象返回出去。

  • 當Message被Handler處理完後,Looper對象會調用Message#recycleUnchecked()將Message進行回收,並存儲到靜態Message鏈表中。

3.三、Handler兩條發送路徑:sendMessage 和 post

咱們都知道,Handler能夠經過sendMessage和post進行消息的發送,這兩種方法到底有什麼區別?先從sendMessage看起:

#Handler.java

public final boolean sendMessage(Message msg){
    //發送一個0延遲的message
    return sendMessageDelayed(msg, 0);
}

public final boolean sendMessageDelayed(Message msg, long delayMillis){
	//延遲值不能小於0
    if (delayMillis < 0) {
        delayMillis = 0;
    }
    //將延遲的時間和開機時間相加
    return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}

public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
	//獲取Handler建立時存儲的當前線程的MessageQueue
     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) {
	//將Message的目標TargetHandler設置爲當前Handler
    //若是經過Handler#obtainMessage()獲取的Message早設置了TargetHandler爲當前Handler,通常是新new的Message才爲空。
    msg.target = this;
    if (mAsynchronous) {
         msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}
複製代碼複製代碼

一路都是方法的嵌套,其中最關鍵的就是在傳遞給sendMessageAtTime()方法前,將延時時間和手機開機時間相加,獲得Message對象的"執行時間"。

在繼續查看MessageQueue#enqueueMessage():

#MessageQueue.java

//標記MessageQueue#next()的nativePollOnce()是否以 非零超時等待(無限等待)被阻止。
private boolean mBlocked;

boolean enqueueMessage(Message msg, long when) {
    //.....

    synchronized (this) {
        //...
        
        msg.markInUse();
        //將延遲時間和開機時間相加獲得的時間值存儲到message的when變量中。
        msg.when = when;
        //獲取鏈表表頭的Message
        Message p = mMessages;
        boolean needWake;
        //當表頭爲空時,或者本次發送的Message對象「執行時間」比表頭的時間要小時
        if (p == null || when == 0 || when < p.when) {
          	//將本次發送的Message存儲到表頭前面,將next屬性指向原鏈表表頭
            msg.next = p;
            //刷新MessageQueue中指向表頭的變量
            mMessages = msg;
            needWake = mBlocked;
        } else {
            //一般不須要喚醒事件隊列,除非隊列的頭部有屏障,而且消息是隊列中最先的異步消息。
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            //開啓循環,便利MessageQueue的Message鏈表
            for (;;) {
                //prev先指向原表頭,後續循環中,不斷指向下一個元素
                prev = p;
                //p指向下一個元素
                p = p.next;
                //若是p== null,表示到鏈表的尾部
                //或者本次發送的Message對象的「執行時間」when比下一個元素的「執行時間」要短
                if (p == null || when < p.when) {
                    //推出循環
                    break;
                }
                //...
            }
            //此時,prev指向的Message對象的when 比本次發送的Message對象msg的when小,即「執行時間」比它小。
            //p可能爲空,即鏈表尾;或者p指向的Message對象的when比 比本次發送的Message對象msg的when大,即「執行時間」比它大。
            // 便可能存在 prev.when < msg.when <p.when 或 prev.when < msg.when
            //將msg的next變量指向p所指的對象
            msg.next = p;
            //prev所指向的message對象的next變量指向msg
            prev.next = msg;
        }

        //判斷是否須要喚醒以前在MessageQueue#next()中「陷入沉睡」的nativePollOnce()方法。
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}
複製代碼複製代碼

MessageQueue#enqueueMessage()主要做用是:

一、依據msg.when的大小,按從小到大的順序,將msg插入到MessageQueue的Message鏈表中。

二、對於立刻執行的message,直接喚醒,中止nativePollOnce()的無限等待,讓MessageQueue#next返回繼續執行,從Message鏈表中取出Message,交由Looper對象進行處理。

模擬狀況:
同時發送延遲400毫秒的Message對象 和 延遲300毫秒的Message對象;
100毫秒後,再發送延遲延遲250毫秒的Message對象;

情景分析:

同時發送兩個分別延遲400和延遲300的Message對象,此時系統開機時間 time = SystemClock.uptimeMillis();

延遲400的Message對象:msg400, msg400 .when = time + 400;。
首先進入MessageQueue的Message鏈表,因爲本來Message鏈表爲空,p == null,表頭mMessages指 msg400

延遲300的Message對象:msg300, msg300.when = time + 300;。
進入if(p == null || when == 0 || when < p.when)語句 ,p != null ,msg300.when < msg400.when , msg300.next 指向 msg400,鏈表表頭指向msg300;

100毫秒後,發送延遲延遲250毫秒的Message對象。此時系統開機時間 time2 = SystemClock.uptimeMillis(),相對time 大了100毫秒,即time2 = time + 100毫秒。

延遲250的Message對象:msg250, msg250.when = time2 + 250, 即msg250.when = time + 350。
進入if(p == null || when == 0 || when < p.when)語句,語句不成立,進入遍歷Message鏈表的for循環。when < p.when判斷中,msg250.when > msg300.when,循環繼續。msg250.when < msg400.when,跳出循環。執行msg.next = p; 和 prev.next = msg;兩個語句,即msg250.next = msg400,msg300.next = msg250。

問題4:Looper如何管理Message隊列(即前後發送不一樣延遲時間的Message,Message隊列如何排序)。

回答:Message經過SystemClock.uptimeMillis() + 延遲時間給自身when賦值,經過值的大小做爲執行順序。SystemClock.uptimeMillis() 不根據當前時區的時間變化而變化,只會因開關機而被重置,不然始終自增。
因此能夠根據當前的SystemClock.uptimeMillis() 與Message對象的when對比,知道立刻執行仍是延遲多少秒後才執行。

轉換到Handler#ost()的源碼:

#Handler.java
public final boolean post(Runnable r){
    return  sendMessageDelayed(getPostMessage(r), 0);
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        //若是Message的callback不爲空,則將消息交由Message的callback處理
        handleCallback(msg);
    } else {
        if (mCallback != null) {
            //若是Handler的callback不爲空,則將消息交由Handler的callback處理
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        //最後才交由Handler的handleMessage()方法處理。
        handleMessage(msg);
    }
}

private static void handleCallback(Message message) {
	//只是調用callback的run()方法。
    message.callback.run();
}
複製代碼複製代碼

post()傳遞的Runnable對象會被套上一層Message外殼,最後走和sendMessage()同樣的路線。

Runnable對象將存儲在Message對象的callback對象中。在Handler處理Message時,因爲callback對象不爲空,調用Handler#handleCallback()對Runnable對象調用run()方法,實現Message的處理。

問題3:Handler的sendMessage() 和 post()有什麼區別。

回答:post()會將Runnable對象轉換爲Message對象,並把Runnable對象存儲在Message對象的callback中,而後繼續走sendMessage()的路線。
在Handler處理Message對象時,post()方法產生的Message對象中callback不爲空,由Handler調用Runnable對象的run方法,不會調用handleMessage();

3.四、Message的移除

#Handler.java
public final void removeMessages(int what) {
    mQueue.removeMessages(this, what, null);
}

public final void removeCallbacks(Runnable r){
    mQueue.removeMessages(this, r, null);
}

public final void removeMessages(int what, Object object) {
    mQueue.removeMessages(this, what, object);
}

public final void removeCallbacks(Runnable r, Object token){
    mQueue.removeMessages(this, r, token);
}
複製代碼複製代碼
#MessageQueue.java
void removeMessages(Handler h, int what, Object object) {
	//...
    synchronized (this) {
    	//獲取Message鏈表表頭
        Message p = mMessages;

        //從頭開始尋找,尋找第一個不符合條件的Message。分兩種狀況:
        //一、鏈表表頭直接不符合移除條件,即第一個不符合條件的Message爲鏈表表頭,推出循環。
        //二、鏈表符合移除條件,將鏈表表頭指向原表頭的下一個Message,並回收原鏈表表頭。新的鏈表表頭繼續進行判斷,直到出現不符合移除條件的Message出現。
        //最後鏈表表頭mMessages 和 p都指向第一個不符合條件的Message,前面符合移除條件的Message已被移除。
        while (p != null && p.target == h && p.what == what
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        //從第一個不符合條件的Message對象開始,迭代尋找其下一個Message是否符合移除條件。
        while (p != null) {
            Message n = p.next;
            if (n != null) {
            	//判斷是否符合移除條件
                if (n.target == h && n.what == what
                    && (object == null || n.obj == object)) {
                    //獲取p.next().next()的Message對象,即下下個對象。
                    Message nn = n.next;
                    //符合條件的回收
                    n.recycleUnchecked();
                    //將本來的下下個Message轉移到next對象中,即轉移到下一個Message的位置上。
                    p.next = nn;
                    continue;
                }
            }
            //n == null,表示到鏈尾了,則 p == null,while循環結束。
            p = n;
        }
    }
}

void removeMessages(Handler h, Runnable r, Object object) {
    if (h == null || r == null) {
        return;
    }
    synchronized (this) {
        Message p = mMessages;

        // Remove all messages at front.
        while (p != null && p.target == h && p.callback == r
               && (object == null || p.obj == object)) {
            Message n = p.next;
            mMessages = n;
            p.recycleUnchecked();
            p = n;
        }

        // Remove all messages after front.
        while (p != null) {
            Message n = p.next;
            if (n != null) {
                if (n.target == h && n.callback == r
                    && (object == null || n.obj == object)) {
                    Message nn = n.next;
                    n.recycleUnchecked();
                    p.next = nn;
                    continue;
                }
            }
            p = n;
        }
    }
}
複製代碼複製代碼

removeMessages(Handler, int, Object) 根據Message中的what進行刷選移除對象。
removeMessages(Handler, Runnable,Object)則根據相同的Runnable對象進行刷選移除。

二者的都是走相同的移除對象流程,只是其中的一種刷選條件有所不一樣,what針對的是Handler#sendMessage()發送的Message,Runnable針對的是Handler#post()發送的Message。

Handler#removeCallbacksAndMessages()則移除這兩種刷選條件,針對全部Message。

問題5:removeCallbacks、removeMessages 和 removeCallbacksAndMessages都移除了什麼

回答:removeCallbacks、removeMessages 和 removeCallbacksAndMessages 在待處理的Message鏈表中,根據各自的刷選條件尋找符合移除條件的對象,將符合條件的Message移除出Message鏈表,並回收該Message。

4、總結

  • Message對象中擁有一個Message類型的next對象,可經過next屬性連成一個Message鏈表。
  • Message類中維繫着個靜態Message鏈表,存儲着回收的Message對象,等待重複使用。
  • MessageQueue類中也維繫着個靜態Message鏈表,存儲着待處理的Message的對象,等待MessageQueue#next()方法將其取出,交由目標Handler處理。
  • 當用戶調用Handler#obtainMessage()時,嘗試從該Message鏈表中獲取待循環再用的Message,獲取失敗則new一個新的Message對象。
    當Message被目標Handler處理完成後,會被回收到Message類的靜態Message鏈表中。
    當調用Handler一系列remove方法後,被移除的Message會被回收到Message類的靜態Message鏈表中。
  • post方法發送的Runnable對象將會被包裝成一個Message走sendMessage路線,Runnable對象被存儲在Message的callback變量中。
  • 當該Message對象的callback爲空,目標Handler的callback也爲空時,纔將Message交由handleMessage()進行處理。即post方法產生的Message對象會被交由Handler#handleCallback()直接調用run方法,不走Handler#handleMessage()。
  • msg.when = 延時時間 + 手機開機時間。再依據msg.when的大小,按從小到大的順序,將msg插入到MessageQueue的Message鏈表中。
  • Looper類中的靜態ThreadLocal常量做爲key,當前線程的Looper對象作爲value,存儲在當前線程的ThreadLocal.ThreadLocalMap變量。ThreadLocal常量確保key惟一,也就確保value惟一,而且Looper#prepare()只容許建立一遍Looper對象。
相關文章
相關標籤/搜索