Handler簡單回顧流程

初學android,我們總是被告誡,不能在子線程中更新界面,請用handler。

本文就帶大家淺顯的理解handler更新界面原理,儘量避免過多源碼分析,只貼關鍵代碼幫助記憶。

目錄:

  • handler的人物交代
  • 更新界面的流程
  • 拓展和疑問

handler中存在的重要角色

Handler

handle 字面意思:操作,搬運;在程序中理解成搬運工,操作員。
搬運什麼呢?搬運消息;什麼消息?更新界面的消息。
就這麼簡單。

MessageQueue

messageQueue中文翻譯過來叫:消息隊列;
那麼handler搬運的消息去哪裏了?就放在這個隊列中,可以想象成一堆消息排隊中,handler搬來的消息都放在了這裏,等待被消耗。

Looper

loop中文叫循環;
循環幹什麼?不停的從消息隊列中獲取消息。

handler更新流程

  • new一個handler(就和new一個女朋友一樣簡單)
/**
 * 1.在UI線程新建handler
 */
fun initHandler() {
    mainHandler = @SuppressLint("HandlerLeak")
    object : Handler() {
        override fun handleMessage(msg: Message?) {
            super.handleMessage(msg)
            //接收不同的消息,做不同的處理
        }
    }
}
  • 通過handler發送消息
/**
 * 2.發送消息
 */
fun sendMessage(){
    mainHandler.sendMessage(Message())
}

handler有各式各樣的send方法,最終都調用sendMessageAtTime方法

//msg:handler搬運的消息
//uptiomeMillis:延時發送 單位 ms
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);//放入消息隊列
}

此方法的最終目的就是把消息放到隊列中

boolean enqueueMessage(Message msg, long when) {
...其他無關代碼...
        msg.markInUse();
        msg.when = when;//消息的發送時間
        Message p = mMessages;
        boolean needWake;
        if (p == null || when == 0 || when < p.when) {
            //如果消息隊列是空的;
              //when==0 代表消息立即處理;
              //when<p.when 代表處理的消息最緊急
              //滿足這些條件,就把消息放在隊列最前面
            msg.next = p;
            mMessages = msg;
            needWake = mBlocked;
        } else {
            needWake = mBlocked && p.target == null && msg.isAsynchronous();
            Message prev;
            for (;;) {
                prev = p;
                p = p.next;
                if (p == null || when < p.when) {
                    //在消息隊列根據when的先後順序,尋找新消息插入的位置
                    break;
                }
                if (needWake && p.isAsynchronous()) {
                    needWake = false;
                }
            }
              //把消息插入隊列中
            msg.next = p; // invariant: p == prev.next
            prev.next = msg;
        }
        if (needWake) {
            nativeWake(mPtr);
        }
    }
    return true;
}

通過對消息隊列的添加策略,我們得知,消息隊列是按照消息執行的先後時間排序的。when越小,排在越前面;
讀懂源碼的知識點:數據結構中隊列的結構和操作。

  • Looper開啓循環,從消息隊列中獲取消息

Looper.loop();//開啓Looper,該幹活了

Message msg = queue.next();//獲取新的消息

for (;;) {
    if (nextPollTimeoutMillis != 0) {
        Binder.flushPendingCommands();
    }
    //從隊列中拉取消息,nextPollTimeoutMillis=0表示立即拉取
    nativePollOnce(ptr, nextPollTimeoutMillis);

    synchronized (this) {
        final long now = SystemClock.uptimeMillis();
        Message prevMsg = null;
        Message msg = mMessages;
        if (msg != null && msg.target == null) {
            do {
                prevMsg = msg;
                msg = msg.next;
            } while (msg != null && !msg.isAsynchronous());
        }
        if (msg != null) {
            if (now < msg.when) {
                // now:當前時間     msg.when:消息的通知時間
                // 消息的通知時間還不到,計算下次拉取message的時間
                nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
            } else {
                // 消息現在可以執行了,把當前消息從隊列中拿出來
                mBlocked = false;
                if (prevMsg != null) {
                    prevMsg.next = msg.next;
                } else {
                    mMessages = msg.next;
                }
                msg.next = null;
                if (DEBUG) Log.v(TAG, "Returning message: " + msg);
                msg.markInUse();
                //返回執行的消息
                return msg;
            }
        } else {
            nextPollTimeoutMillis = -1;
        }

        if (mQuitting) {
            dispose();
            return null;
        }
}

最後調用dispatchMessage通知handler做相應的界面更新

總結一下就是:handler發送消息,MessageQueue保存消息,Looper循環取出消息通知更新界面。

其他handler的細節和知識點在下節分析~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章