Handler + Looper + MessageQueue詳解

一、使用詳解

(1)Handler使用

//創建一個帶有Looper的線程
class LooperThread extends Thread{
    @Override
    public void run() {
        Looper.prepare();
        Looper.loop();
    }
}

//在主線程中創建,自動綁定主線程Looper
private Handler uiHandler = new Handler() {
    //重寫Handler的處理消息的方法handleMessage()
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case 1:
                break;
        }
    }
};
//獲取子線程實例
LooperThread looperThread = new LooperThread();
//開啟子線程
looperThread.start();
//獲取子線程Looper
Looper loop = looperThread .getLooper();
//手動綁定子線程Looper
private Handler mHandler = new Handler(loop) {
    //重寫Handler的處理消息的方法handleMessage()
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case 1:
                break;
        }
    }
};
//發送消息
Message message = new Message();
message.what = 1;
message.obj = "result";
uiHandler.sendMessage(message )
mHandler.sendMessage(message )

(2)Handler構造方法

  • Handler():構造函數將通過調用Looper.myLooper()獲取當前線程綁定的Looper對象,將該Looper對象保存到名為mLooper的成員字段中。
  • Handler(Looper looper):直接將該Looper保存到名為mLooper的成員字段中。
  • Handler(Callback callback):構造函數傳遞了Callback對象,Callback是Handler中的內部接口,需要實現其內部的handleMessage方法。
  • Handler(Looper looper, Callback callback)
    處理Message消息,通過實現Handler.Callback的handleMessage方法或重寫Handler本身的handleMessage方法

多線程實現:向Thread的post函數傳入一個Runnable對象者重寫Thread本身的run方法。

二、源碼解析

(1)Handler源碼
Handler的創建

    public Handler() {
        this(null, false);
    }

    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());
            }
        }
        //獲取當前線程的Looper對象
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        //獲取當前Looper的消息隊列MessageQueue對象
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

Handler.sendMessage發送消息

    public final boolean sendMessage(Message msg)
    {
        return sendMessageDelayed(msg, 0);
    }

    public final boolean sendMessageDelayed(Message msg, long delayMillis)
    {
        if (delayMillis < 0) {
            delayMillis = 0;
        }
        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
    }

    public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
        //Handler所綁定的消息隊列MessageQueue
        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);
    }

    private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        //將Message的target綁定為當前的Handler
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        //通過queue.enqueueMessage(msg, uptimeMillis)我們將Message放入到消息隊列中。
        return queue.enqueueMessage(msg, uptimeMillis);
    }

Handler.dispatchMessage發送消息到Handler

    //派發消息到對應的Handler實例。根據傳入的msg作出對應的操作
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            //使用了post發送消息,則執行handleCallback方法,回調Runnable復寫的run方法
            handleCallback(msg);
        } else {
            //使用了sendMessage發送消息,則執行handleMessage,回調復寫的handleMessage
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }

(2)Looper創建源碼
Looper.prepare()創建Looper,當前線程和Looper就進行了雙向的綁定

    //Looper對象中通過sThreadLocal就可以找到其綁定的線程
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

    public static void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        //1個線程中只能對應1個Looper實例
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        //創建Looper對象存放在ThreadLocal變量中
        sThreadLocal.set(new Looper(quitAllowed));
    }
    
    private Looper(boolean quitAllowed) {
        //創建消息隊列對象
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

Looper.loop()循環獲取MessageQueue中消息Message

    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.");
        }
        //獲取當前線程所關聯的消息隊列
        final MessageQueue queue = me.mQueue;

        //code...

        //消息循環
        for (;;) {
            //從消息隊列中取出消息
            Message msg = queue.next(); // might block
            //若取出的消息為空,則線程阻塞
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }
            //code...
            try {
                //Message所關聯的Handler通過dispatchMessage方法讓Handler處理該Message
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            //code...
            //釋放消息占據的資源
            msg.recycleUnchecked();
        }
    }

Looper類還提供了一些有用的方法

    //獲取當前線程的Looper
    public static @Nullable Looper myLooper() {
        return sThreadLocal.get();
    }
    //獲取looper對象所屬線程
    public Thread getThread() {
        return mThread;
    }
    //結束looper循環
    public void quit() {
        // 創建一個空的message,它的target為NULL,表示結束循環消息  
        Message msg = Message.obtain();
        // 發出消息  
        mQueue.enqueueMessage(msg, 0);
}

(3)MessageQueue源碼
MessageQueue.enqueueMessage將一個Message放入到消息隊列MessageQueue中

    boolean enqueueMessage(Message msg, long when) {
        //code...
        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) {
                //消息隊列無消息將當前插入的消息作為隊頭,若此時消息隊列處于等待狀態,則喚醒
                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) {
                        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;
    }

MessageQueue.next從消息隊列MessageQueue中阻塞式地取出一個Message

Message next() {
        //code...
        //確定消息隊列中是否還有消息。從而決定消息隊列應處于出隊消息狀態還是等待狀態
        int nextPollTimeoutMillis = 0;
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }
            //若是nextPollTimeoutMillis為-1,此時消息隊列處于等待狀態
            nativePollOnce(ptr, nextPollTimeoutMillis);

            synchronized (this) {
                // Try to retrieve the next message.  Return if found.
                final long now = SystemClock.uptimeMillis();
                Message prevMsg = null;
                Message msg = mMessages;
                //從消息隊列中取出消息:按創建Message對象的時間順序
                if (msg != null && msg.target == null) {
                    // Stalled by a barrier.  Find the next asynchronous message in the queue.
                    do {
                        prevMsg = msg;
                        msg = msg.next;
                    } while (msg != null && !msg.isAsynchronous());
                }
                if (msg != null) {
                    if (now < msg.when) {
                        // Next message is not ready.  Set a timeout to wake up when it is ready.
                        nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
                    } else {
                        // Got a message.
                        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 {
                    // No more messages.
                    //消息隊列中已無消息,則將nextPollTimeoutMillis參數設為-1。下次循環時,消息隊列則處于等待狀態
                    nextPollTimeoutMillis = -1;
                }
                //code...
            }
            //code...
        }
    }

(4)Message源碼

    //Message內部維護了一個Message池,用于Message消息對象的復用
    public static Message obtain() {
        synchronized (sPoolSync) {
            if (sPool != null) {
                Message m = sPool;
                sPool = m.next;
                m.next = null;
                m.flags = 0; // clear in-use flag
                sPoolSize--;
                return m;
            }
        }
        //若池內無消息對象可復用,則還是用關鍵字new創建
        return new Message();
    }
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容