Handler消息機(jī)制源碼分析

1.什么是Handler

Handler是android中消息機(jī)制,Handler運(yùn)行需要通過MessageQueue和Looper來支撐,Handler主要作用就是將一個(gè)任務(wù)切換到指定的線程中

2 Handler使用

發(fā)送三個(gè)消息,通過這三個(gè)來分析MessageQueue

public class HandlerActivity extends AppCompatActivity {
    private TextView tv;
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            tv.setText(msg.obj + "");
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler);
        tv = findViewById(R.id.tv);
        //開啟一個(gè)線程發(fā)送消息
        new Thread(new Runnable() {
            @Override
            public void run() {
                Message msg1 = Message.obtain();
                msg1.obj = "姚明1";
                mHandler.sendMessage(msg1);

                Message msg2 = Message.obtain();
                msg2.obj = "姚明2";
                mHandler.sendMessageDelayed(msg2,1000);

                Message msg3 = Message.obtain();
                msg3.obj = "姚明3";
                mHandler.sendMessageDelayed(msg3,500);
            }
        }).start();
    }
}

3.MessageQueue消息隊(duì)列

線程中更新 UI 的時(shí)候經(jīng)常是調(diào)用 sendMessage() 和 sendMessageDelayed() ,看一下sendMessage() 方法

    //默認(rèn)延時(shí)時(shí)間為0
    public final boolean sendMessage(@NonNull Message msg) {
      return sendMessageDelayed(msg, 0);
    }
    
    public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
       return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }
    
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        ...
        return enqueueMessage(queue, msg, uptimeMillis);
    }
    
    private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
            long uptimeMillis) {
        //注意這里,msg.target綁定了我們的this也就是Handler
        msg.target = this;
        ....
        return queue.enqueueMessage(msg, uptimeMillis);
    }
3.1MessageQueue的核心代碼
    boolean enqueueMessage(Message msg, long when) {

        synchronized (this) {
            ....
            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;
    }

通過上邊的這些代碼,我們暫時(shí)還沒有看到 Handler 調(diào)用 handleMessage() 方法,但是有了一個(gè)重要的結(jié)論,我們每次發(fā)送一個(gè)消息都會(huì)被保存到了 MessageQueue 消息隊(duì)列中,消息隊(duì)列中采用的是單鏈表的方式。通過用下面這段代碼發(fā)送消息,在 MessageQueue 中如圖所示。

3.2.MessageQueue內(nèi)如圖所示
    Message msg1 = Message.obtain();
    msg1.obj = "姚明1";
    mHandler.sendMessage(msg1);
    
    Message msg2 = Message.obtain();
    msg2.obj = "姚明2";
    mHandler.sendMessageDelayed(msg2,1000);
    
    Message msg3 = Message.obtain();
    msg3.obj = "姚明3";
    mHandler.sendMessageDelayed(msg3,500);
在這里插入圖片描述
3.3 總結(jié)

???每次發(fā)送一個(gè)消息都會(huì)添加到消息隊(duì)列中,按照when時(shí)間進(jìn)行排序,消息隊(duì)列采用的是單鏈表形式。

4.Loop消息循環(huán)

4.1 子線程中使用Handler

先看一種現(xiàn)象,有時(shí)候我們像下面這么寫會(huì)報(bào)錯(cuò):

     new Thread(new Runnable() {
            @Override
            public void run() {
                //子線程中使用Handler
                Handler handler = new Handler();
            }
        }).start();

在這里插入圖片描述

必須要這樣寫

    new Thread(new Runnable() {
        Override
        public void run() {
            //1.創(chuàng)建Looper對(duì)象,獲取當(dāng)前線程,通過當(dāng)前線程獲取ThreadLocalMap對(duì)象,保證一個(gè)線程只有一個(gè)Looper對(duì)象
            Looper.prepare();
            //2.獲取當(dāng)前的Looper對(duì)象,獲取當(dāng)前的MessagerQueue對(duì)象
            Handler handler = new Handler();
            //3.發(fā)送消息,將消息添加到消息隊(duì)列中,通過msg.when來進(jìn)行排序
            Message msg = Message.obtain();
            msg.obj = "姚明"
            handler.sendMessage(msg);
            //4.獲取當(dāng)前的Looper對(duì)象,獲取當(dāng)前的MessagerQueue對(duì)象,通過死循環(huán)不斷獲取MessageQueue中消息,回掉給Handler的handlerMessage。
            Looper.loop();
        }
    }).start();

我們?cè)谥骶€程中從來沒有調(diào)用過Looper.prepare();這行代碼,為什么就不會(huì)報(bào)錯(cuò)呢。因?yàn)樵谖覀兂绦蛉肟贏ctivityThread中的入口函數(shù) main() 已經(jīng)幫我們調(diào)用了這行代碼

    public static void main(String[] args) {
        //....省略部分代碼
        
        Looper.prepareMainLooper();

        ActivityThread thread = new ActivityThread();
        thread.attach(false, startSeq);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }
        
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
4.2 Looper.prepare()分析

我們來通過看源碼來了解Looper.prepare()到底干了什么。

    //靜態(tài)的
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    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));
    }

    /**
    *  1.獲取當(dāng)前線程,通過當(dāng)前線程獲取線程的ThreadLocalMap對(duì)象,一個(gè)線程只有一個(gè)ThreadLocal對(duì)象
    *  2.如果map不為空,就添加,key就是我們的sThreadLocal是靜態(tài)的,value就是我們的Looper對(duì)象。
    *  3.如果map為空就會(huì)創(chuàng)建ThreadLocalMap
    */
    public void set(T value) {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    //創(chuàng)建ThreadLocalMap
    void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

    //創(chuàng)建MessageQueue,獲取當(dāng)前線程。
     private Looper(boolean quitAllowed) {
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }
4.2.1 總結(jié)

???Looper.prepare() 就是創(chuàng)建了Looper對(duì)象,通過當(dāng)前線程獲取ThreadLocalMap,通過set來保證一個(gè)線程中只有一個(gè)Looper對(duì)象

4.3 Looper.loop()解析
    public static void loop() {
        //1.獲取當(dāng)前線程的Looper對(duì)象
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        
        //2.獲取消息隊(duì)列
        final MessageQueue queue = me.mQueue;

        //3.死循環(huán)不斷獲取消息隊(duì)列中的消息
        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            try {
                //msg.target就是我們的Handler,在MessageQueue中已經(jīng)提到了msg.target綁定了我們的Handler,可以回去看一下
                //3.通過 Handler 執(zhí)行我們Message,這里邊就調(diào)用我們的handleMessage方法
                msg.target.dispatchMessage(msg);
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            //回收我們的消息
            msg.recycleUnchecked();
        }
    }


    /**
     * Handle system messages here.
     */
    public void dispatchMessage(@NonNull Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                //4.回掉我們的handleMessage
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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