Android的Handler消息機(jī)制 解析

Android的Handler消息機(jī)制

實(shí)現(xiàn)原理

  1. 主線程會(huì)自動(dòng)調(diào)用Looper.prepareMainLooper和Looper.loop,具體是在ActivityThread中main方法中調(diào)用的。
public static void main(String[] args) {
    ......省略無關(guān)代碼
    
    // 主線程的Looper相關(guān)準(zhǔn)備工作
    Looper.prepareMainLooper();

    // Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
    // It will be in the format "seq=114"
    long startSeq = 0;
    if (args != null) {
        for (int i = args.length - 1; i >= 0; --i) {
            if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
                startSeq = Long.parseLong(
                        args[i].substring(PROC_START_SEQ_IDENT.length()));
            }
        }
    }
    // 生成主線程
    ActivityThread thread = new ActivityThread();
    thread.attach(false, startSeq);
    
    // 拿到主線程的Handler,并將主線程的Looper綁定到Handler中
    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);
    // 開啟消息循環(huán)
    Looper.loop();

    throw new RuntimeException("Main thread loop unexpectedly exited");
}
  1. 子線程使用Handler時(shí),首先需要調(diào)用Looper.prepare,prepare方法中,new一個(gè)Looper對(duì)象,存入ThreadLocal;在Looper的構(gòu)造中,會(huì)new一個(gè)MessageQueue,綁定到當(dāng)前Looper中。
private static void prepare(boolean quitAllowed) {
    if (sThreadLocal.get() != null) {
        throw new RuntimeException("Only one Looper may be created per thread");
    }
    // new一個(gè)Looper對(duì)象
    sThreadLocal.set(new Looper(quitAllowed));
}

private Looper(boolean quitAllowed) {
    // new一個(gè)MessageQueue,綁定到Looper中
    mQueue = new MessageQueue(quitAllowed);
    mThread = Thread.currentThread();
}
  1. 創(chuàng)建Handler實(shí)例,在Handler構(gòu)造中,若傳入Looper,則將傳入的Looper綁定給Handler的Looper,并將傳入Looper的MessageQueue也綁定給Handler的MessageQueue。若不傳入Looper,則構(gòu)造中,直接取當(dāng)前線程的Looper以及該Looper的MessageQueue和handler綁定。
// 創(chuàng)建Handler選擇無參構(gòu)造,會(huì)走到這里
public Handler(Callback callback, boolean async) {
    if (FIND_POTENTIAL_LEAKS) {
        final Class<? extends Handler> klass = getClass();
        if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                (klass.getModifiers() & Modifier.STATIC) == 0) {
            Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                klass.getCanonicalName());
        }
    }
    // 拿到當(dāng)前線程的Looper,綁定到Handler中
    mLooper = Looper.myLooper();
    if (mLooper == null) {
        throw new RuntimeException(
            "Can't create handler inside thread " + Thread.currentThread()
                    + " that has not called Looper.prepare()");
    }
    // 拿到當(dāng)前線程Looper的MessageQueue,綁定到Handler中
    mQueue = mLooper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}

// 創(chuàng)建Handler選擇有參構(gòu)造,會(huì)走到這里
public Handler(Looper looper, Callback callback, boolean async) {
    // 將傳入的Looper以及該Looper的MessageQueue綁定到Handler中,讓Handler在Looper所在的線程環(huán)境中
    mLooper = looper;
    mQueue = looper.mQueue;
    mCallback = callback;
    mAsynchronous = async;
}
  1. 接著調(diào)用Looper.loop,拿到myLooper,也就是從ThreadLocal中取,在拿到myLooper的MessageQueue,對(duì)MessageQueue死循環(huán),MessageQueue.next()獲取消息,沒有消息則掛載。有消息時(shí),會(huì)調(diào)用message的target的dispatchMessage方法分發(fā)消息。dispatchMessage方法中,首先判斷message是否有回調(diào),有則直接將新消息傳遞給回調(diào)接口的run方法中。若message沒有回調(diào),則再判斷handler是否有回調(diào),有回調(diào),則將新消息傳遞給回調(diào)接口的handleMessage方法中。若handler也沒有回調(diào),則將消息傳遞給handler的handleMessage公開方法中。外部重寫該方法即可接收處理新消息。
public static void loop() {
    // 拿到Looper
    final Looper me = myLooper();
    if (me == null) {
        throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
    }
    // 拿到Looper的MessageQueue
    final MessageQueue queue = me.mQueue;

    ......省略無關(guān)代碼
    
    // 對(duì)MessageQueue死循環(huán)
    for (;;) {
        // MessageQueue.next()獲取消息
        Message msg = queue.next(); // might block
        // 沒有消息則掛載
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }

        ......省略無關(guān)代碼
        
        try {
            // 有消息時(shí),調(diào)用message的target的dispatchMessage方法分發(fā)消息
            msg.target.dispatchMessage(msg);
            dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }
        
        ......省略無關(guān)代碼
        
        msg.recycleUnchecked();
    }
}

// Handler分發(fā)消息
public void dispatchMessage(Message msg) {
    // Message有回調(diào),則直接將新消息傳遞給回調(diào)接口的run方法中
    if (msg.callback != null) {
        handleCallback(msg);
    } else {
        // Handler有回調(diào),則將新消息傳遞給回調(diào)接口的handleMessage方法中
        if (mCallback != null) {
            if (mCallback.handleMessage(msg)) {
                return;
            }
        }
        // 將消息傳遞給handler的handleMessage公開方法中
        handleMessage(msg);
    }
}
  1. hander.sendMessage,會(huì)調(diào)用enqueueMessage方法,將當(dāng)前handler賦值給Message的target,然后調(diào)用handler的MessageQueue的enqueueMessage方法,內(nèi)部會(huì)將新的message添加進(jìn)MessageQueue中。此時(shí),Looper中MessageQueue會(huì)被喚醒,循環(huán)獲取到新消息做下一步處理。
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
    // 將當(dāng)前handler賦值給Message的target
    msg.target = this;
    if (mAsynchronous) {
        msg.setAsynchronous(true);
    }
    // 調(diào)用MessageQueue的enqueueMessage方法,內(nèi)部會(huì)將新的message添加進(jìn)MessageQueue鏈表中
    return queue.enqueueMessage(msg, uptimeMillis);
}

相關(guān)概念

  • 一個(gè)線程對(duì)應(yīng)一個(gè)Looper,一個(gè)Looper對(duì)應(yīng)一個(gè)MessageQueue,一個(gè)Looper可對(duì)應(yīng)多個(gè)Handler,一個(gè)Handler對(duì)應(yīng)一個(gè)Looper。
  • 主線程中,MessageQueue死循環(huán),并不會(huì)卡死UI。在ActivityThread的main方法中,首先調(diào)用Looper.prepareMainLooper,緊接著就會(huì)new一個(gè)ActivityThread,并且拿到該主線程的mainThreadHandler,再調(diào)用Looper的loop開啟消息循環(huán)。以后UI線程的UI刷新等操作也是在mainThreadHandler發(fā)消息執(zhí)行的。
最后編輯于
?著作權(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)容