Adnroid源碼學(xué)習(xí)筆記:Handler 線程間通訊

常見(jiàn)的使用Handler線程間通訊:

//主線程:
Handler handler = new Handler() {
@Override
    public void handleMessage(Message msg) {
        ...
    }
};

//子線程:
Message message = new Message();  
message.arg1 = 1;  
Bundle bundle = new Bundle();  
bundle.putString("test", "test");  
message.setData(bundle);  
handler.sendMessage(message); 

這類操作一般用于在子線程更新UI。在主線程創(chuàng)建一個(gè)handler,重寫handlermessage方法,然后在子線程里發(fā)送消息,主線程里就會(huì)接受到消息。這就是簡(jiǎn)單的線程間通訊。

如果在子線程創(chuàng)建handler對(duì)象則會(huì)報(bào)錯(cuò)。根據(jù)Log提示,子線程創(chuàng)建handler需要調(diào)用Looper.prepare() (在main函數(shù)中已經(jīng)調(diào)用了Looper.prepareMainLooper(),該方法內(nèi)會(huì)調(diào)起Looper.prepare()),Looper.loop()方法 。但是即使子線程調(diào)用Looper.prepare()創(chuàng)建Looper對(duì)象,這個(gè)Looper也是子線程的,不可以用于更新UI操作。

那到底Handler、Looper這幾個(gè)類之間是如何工作的呢?我們從源頭看起,以下是Looper類的prepare()方法:

public final class Looper { 
    ...
    final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); //threadLocal是線程內(nèi)部的數(shù)據(jù)存儲(chǔ)類,該類存儲(chǔ)了線程的所有數(shù)據(jù)信息。

    public static void prepare() {
        prepare(true);
    }
    
    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)); //創(chuàng)建一個(gè)Looper(Looper的構(gòu)造器里也創(chuàng)建了一個(gè)MessageQueue,),將Looper與線程關(guān)聯(lián)起來(lái)
    }

    public static @Nullable Looper myLooper() { //下面會(huì)看到的,設(shè)置Handler類里的Looper時(shí)會(huì)調(diào)用該方法
        return sThreadLocal.get(); //獲得Looper對(duì)象
    }
    ...
}

當(dāng)handler傳輸message時(shí),不論是調(diào)用sendMessage(Message msg)還是sendMessageDelayed(),最后都會(huì)指向sendMessageAtTime()方法:

public class Handler {    
    ...
    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);
    }
    ...
}

mQueue即消息隊(duì)列,用于將收到的消息以隊(duì)列形式排列,提供出隊(duì)和入隊(duì)方法,該變量是Looper的成員變量,在Handler創(chuàng)建時(shí)賦值給handler

public class Handler {
    ...
    final Looper mLooper;
    final MessageQueue mQueue;
    mLooper = Looper.myLooper();  //創(chuàng)建Handler前調(diào)用Looper.prepare()時(shí)定義并設(shè)置了Looper,這里調(diào)用Looper.myLooper()來(lái)獲得該Looper
    mQueue = mLooper.mQueue;
    ...
}

上面調(diào)用的enqueueMessage(queue, msg, uptimeMillis)方法作用是消息入隊(duì)

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    msg.target = this; //把handler本身賦值給要入隊(duì)的消息,用來(lái)待會(huì)兒出隊(duì)使用
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    return queue.enqueueMessage(msg, uptimeMillis);
}

可以看到最后是由消息隊(duì)列queue調(diào)用自身MessageQueue類的入隊(duì)方法enqueueMessage()

boolean enqueueMessage(Message msg, long when) {
    if (msg.target == null) {
        throw new IllegalArgumentException("Message must have a target.");
    }
    if (msg.isInUse()) {
        throw new IllegalStateException(msg + " This message is already in use.");
    }

    synchronized (this) {
        if (mQuitting) {
            IllegalStateException e = new IllegalStateException(
                        msg.target + " sending message to a Handler on a dead thread");
            Log.w(TAG, e.getMessage(), e);
            msg.recycle();
            return false;
        }

        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 {
            // 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;
        }

        // We can assume mPtr != 0 because mQuitting is false.
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

mMessages是MessageQueue類的一個(gè)成員變量,用以記錄排在最前面的消息,msg是我們傳入的message,msg.next是Message類的成員變量,可以理解成下一條消息。入列方法重點(diǎn)看這幾句:

Message p = mMessages;
msg.next = p;  //把mMessages賦值給新入隊(duì)的這條消息的next
mMessages = msg;  //把新入隊(duì)的消息賦值給mMessages

就像排隊(duì)一樣,msg是來(lái)插隊(duì)的,排第一的mMessages自愿排到msg的后面,并讓msg站到自己原來(lái)的位置上,這樣就完成的msg的入隊(duì)操作,整個(gè)消息入隊(duì)操作是按照時(shí)間來(lái)排序的。至于出隊(duì)操作,就在一開(kāi)始所提到的ActivityTread中的main方法里調(diào)用的Looper.loop()方法里:

public static void loop() {
    ...

    for (;;) {
        ...
        Message msg = queue.next(); //獲取下一條消息
        ...
        msg.target.dispatchMessage(msg); //傳遞消息
        ...
        msg.recycleUnchecked(); //清空狀態(tài),循環(huán)往復(fù)
        }
    }
    ...
}

提煉出來(lái)就是在loop方法里一直死循環(huán),從MessageQueue消息隊(duì)列里使用next()方法獲得下一條消息,next方法簡(jiǎn)單看就是:

Message msg = mMessages;
mMessages = msg.next;
msg.next = null;
return msg;

這就是簡(jiǎn)單的解釋消息出列,把排第一的消息作為方法的返回值,然后讓排第二的排到第一去。獲得消息后使用msg.target(上面入隊(duì)時(shí)賦值的handler)來(lái)傳遞消息:

public void dispatchMessage(Message msg) {
    if (msg.callback != null) {
        handleCallback(msg); //如果有callback參數(shù)則調(diào)用處理回調(diào)的方法
    } else {
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        handleMessage(msg); //將消息作為參數(shù)傳遞出去
    }
}

至此,handler傳遞消息的整個(gè)流程走完。另外還有一個(gè)我們經(jīng)常用到handler的方法post:

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

private static Message getPostMessage(Runnable r) { //將runnable變成message自身的callback變量
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

可以看到,post的runnable參數(shù)經(jīng)過(guò)getPostMessage()方法最后被賦值給要傳遞下去的消息的callback這個(gè)變量,等到消息出列時(shí),如果消息帶有callback參數(shù)則調(diào)用處理回調(diào)的方法handleCallback(msg)

private static void handleCallback(Message message) {
    message.callback.run();
}

可以看到,不論是從sendMessage里發(fā)出的消息,還是在post傳遞的runnable里執(zhí)行的代碼,最后都是殊途同歸,都是在UI線程運(yùn)行的。最后總結(jié)一下吧,線程間通訊原理大概就是:

  1. Looper.prepare()創(chuàng)建Looper和MessageQueue,并與所在線程關(guān)聯(lián)
  2. Looper.loop()通過(guò)一個(gè)for死循環(huán)不斷對(duì)MessageQueue進(jìn)行輪詢
  3. 創(chuàng)建handler時(shí),會(huì)把Looper和MessageQueue賦值給handler,將三者關(guān)聯(lián)起來(lái)。當(dāng)handler調(diào)用sendMessage傳遞消息,消息會(huì)被發(fā)送到Looper的消息隊(duì)列MessageQueue里
  4. 一旦loop()方法接收到消息,則將消息通過(guò)該消息攜帶的handler(msg.target)的handleMessage方法處理
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容