Handler 原理

1.為什么要用Handler

在Android中主線程又稱為UI線程,負責(zé)創(chuàng)建和更新UI,其他耗時操作如,訪問數(shù)據(jù)庫,網(wǎng)絡(luò)請求,操作文件IO都需要放在子線程中執(zhí)行。
Android屏幕刷新大概是1秒60幀,每幀間隔16.67毫秒,為了保證刷新不掉幀,所以將耗時操作全部放在子線程中處理。
當(dāng)子線程處理完數(shù)據(jù)之后,為了防止UI處理邏輯的混亂,Android只允許主線程處理UI,這時候需要Handler來充當(dāng)子線程和主線程之間的橋梁。

為什么不加鎖:

1.鎖會讓UI邏輯混亂,無法保證執(zhí)行順序。
2.鎖會降低UI更新效率,會阻塞某些線程的執(zhí)行。
3.Android利用Handler隱示的添加了一把只能在主線程更新的鎖。因此Handler的消息處理機制是線程安全的
ps:在某些情況下可以在子線程更新UI,例如onCreate ,主線程更新完UI后馬上子線程再次更新UI ,或者在子線程更新固定寬高的控件。

2.Handler消息機制的原理

本質(zhì)就是Handler發(fā)送Message到MessageQueue中,Looper遍歷消息分發(fā)給Hanlder處理。

Handler 主要涉及四個類
1.Message:消息
每個消息的攜帶者持有Handler,存放在MessageQueue中,一個線程可以多個實例。
2.Hanlder:消息的發(fā)起者,處理者
發(fā)送Message及處理回調(diào)事件,一個線程可以存在多個實例。
3.Looper:消息的遍歷者
從MessageQueue中遍歷出每個Message進行處理,一個線程一個實例。
4.MessageQueue:消息隊列
存放Handler發(fā)送的消息,提供給Looper遍歷,一個線程一個。

Looper.prepare()

方法中在ThreadLocal中獲取一個Looper。
因此確保每個線程中只有一個Looper。

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

3.Looper的啟動

ActivityThread作為程序的第一個入口,main方法中調(diào)用Looper.prepareMainLooper創(chuàng)建了一個Looper。
并調(diào)用Looper.loop();方法

    public static void main(String[] args) {
        ...
        Looper.prepareMainLooper();

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

        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);
        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

4.Looper的循環(huán)

    public static void loop() {
        //獲取當(dāng)前線程的Looper對象
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        //獲取對應(yīng)的消息隊列
        final MessageQueue queue = me.mQueue;
        ...
        //死循環(huán)
        for (;;) {
            //在消息隊列中獲取消息
            Message msg = queue.next(); // might block
            if (msg == null) {
                return;
            }
           ...
            try {
                //target 是 Message 中保存處理消息的Handler實例。
                msg.target.dispatchMessage(msg);
            } catch (Exception exception) {
                throw exception;
            }
            ...
            msg.recycleUnchecked();
        }
    }

5.MessageQueue的next();

如果沒有消息可以回去會執(zhí)行nativePollOnce方法陷入沉睡, 等待喚醒。
添加消息到隊列中enqueueMessage方法會進行調(diào)用nativeWake方法喚醒。

6.nativePollOnce 和 nativeWake

目前還無法看懂具體實現(xiàn)。后續(xù)看明白會補上。

    private native void nativePollOnce(long ptr, int timeoutMillis); /*non-static for callbacks*/
    private native static void nativeWake(long ptr);
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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