Android基礎夯實--我們所瞭解的Handler

Handler機制主要用於異步消息的處理:當發出一個消息之後,首先進入一個消息隊列,發送消息的函數即刻返回,而另外一個部分在消息隊列中逐一將消息取出,然後對消息進行處理,也就是發送消息和接收消息不是同步的處理,這種機制適合用來處理相對耗時比較長的操作。
所以在Android中通常用來更新UI,子線程執行任務,任務執行完畢後發送消息:Handler.sendMessage(),然後在UI線程Handler.handleMessage()就會調用,執行相應處理。
Handler機制有幾個非常重要的類:
Handler:用來發送消息:sendMessage等多個方法,並實現handleMessage()方法處理回調(還可以使用Message或Handler的Callback進行回調處理)。
Message:消息實體,發送的消息即爲Message類型。
MessageQueue:消息隊列,用於存儲消息。發送消息時,消息入隊列,然後Looper會從這個MessageQueen取出消息進行處理。
Looper:與線程綁定,不僅僅侷限於主線程,綁定的線程用來處理消息。loop()方法是一個死循環,一直從MessageQueen裏取出消息進行處理。
在這裏需要注意的是:一個線程裏面只會有一個Looper和一個MessageQueue,可以有多個Handler對象,
MessageQueue是在Looper對象創建的時候一起創建的,在Handler創建之前該線程必須先創建好Looper對象,否則將會報以下錯誤:

if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }

整個工作流程圖如下:
在這裏插入圖片描述
接下來開始工作流程源碼的分析:
源碼的分析是根據使用步驟進行:
1.先創建一個Handler

	/**
     * 此處以 匿名內部類 的使用方式爲例
     */
    private Handler mHandler = new Handler(){

        @Override
        public void handleMessage(Message msg) {

        }
    };

當我們在主線程當中,可以直接進行Handler的創建。如果是在子線程當中,在創建之前必須先初始化Looper,否則會RuntimeException;

public Handler(Callback callback, boolean async) {
       // 省略部分的代碼
       // 那當前線程的Looper,如果爲空拋異常
        mLooper = Looper.myLooper();
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread " + Thread.currentThread()
                        + " that has not called Looper.prepare()");
        }
        // 獲得MessageQueue的對象,當Looper創建的時候同時會創建MessageQueue對象
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

在子線程中使用handler除了必須先初始化Looper對象之外,還必須在最後調用Looper.loop()來啓動循環,否則Handler仍然無法正常接收。
而我們平時在主線程中創建handler之所以不用再去創建Looper對象是因爲主線程在初始化的時候就已經跟着創建了一個Looper,就在ActivityThread的main方法裏面

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();在這裏也是會放到最後才執行,開啓一個循環,當Looper.loop();意外退出的時候將會拋異常
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

再點進Looper.prepareMainLooper();裏面,接着往下看可以發現其內部也是調用了prepare(false);方法

		public static void prepareMainLooper() {
		// 在這個方法裏面會創建一個Looper,同時quitAllowed傳false意思是Looper不允許結束循環
        prepare(false);
        synchronized (Looper.class) {
            if (sMainLooper != null) {
                throw new IllegalStateException("The main Looper has already been prepared.");
            }
            sMainLooper = myLooper();
        }
    }
    // 創建Looper的方法
    private static void prepare(boolean quitAllowed) {
    	// 通過ThreadLocal將Looper與當前的線程綁定,也意味着每個線程都是隻有唯一個Looper,當你創建第二個的時候則會報錯
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }
	// 創建Looper時候調用的構造函數
	private Looper(boolean quitAllowed) {
		// 只有當Looper創建的時候纔會同時創建 MessageQueue 對象,所以一個線程裏面只會存在一個Looper和一個MessageQueue
		// 同時對應多個的Handler和Message,而且Looper和MessageQueue都是在Handler和Message尚未創建之前就已經創建好的
        mQueue = new MessageQueue(quitAllowed);
        mThread = Thread.currentThread();
    }

2.當我們使用Handler進行發送消息的時候
Handler發送消息的方式有很多種,包括髮送延時,即時或空的消息,或者是一個Runnable,查看相關的源碼我們會發現最終都是調用了同一個方法MessageQueue的enqueueMessage();

		// Handler發送消息最終會走到的方法
		private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
        msg.target = this;
        if (mAsynchronous) {
            msg.setAsynchronous(true);
        }
        // 最後調用了MessageQueue#enqueueMessage(msg, uptimeMillis);
        return queue.enqueueMessage(msg, uptimeMillis);
    }

繼續追蹤點開查看MessageQueue的enqueueMessage();的全部源碼

		boolean enqueueMessage(Message msg, long when) {
		//Meesage是否可用
        //這裏的msg.target指的就是發送該Message的Handler
        if (msg.target == null) {
            throw new IllegalArgumentException("Message must have a target.");
        }
        if (msg.isInUse()) {
            throw new IllegalStateException(msg + " This message is already in use.");
        }

        synchronized (this) {
        	// 判斷是否調用了quit()方法,即取消信息;如果調用了,說明Looper已經停止了,同時所有的消息都已經被取消
        	// 需要注意的是如果是主線程調用quit()方法將會拋異常
            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) {
                // 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.
            // 如果Looper.loop()是休眠狀態,則調用native方法喚醒loop()
            if (needWake) {
                nativeWake(mPtr);
            }
        }
        return true;
    }

需要注意的一點是,在MessageQueue中Message的保存是以鏈表的形式存儲的,即只有上一個的Message才知道它的下一個Message是誰,而當前的MessageQueue也是不知道的
然後再從Looper.loop()方法中取出消息,繼續追蹤源碼如下:

	public static void loop() {
		// 獲取當前Looper的消息隊列,其中myLooper()作用:返回sThreadLocal存儲的Looper實例;若me爲null 則拋出異常;
		// 即loop()執行前必須執行prepare(),從而創建1個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;
		// 省略中間的部分源碼。。。
		// 開啓循環取出消息
        for (;;) {
        	// 從消息隊列中取出消息,如果是沒有消息的話,在queue.next();阻塞線程
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

           // 省略中間部分代碼

            final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
            final long dispatchEnd;
            try {
            	// 將取出的消息派發到對應的Handler
                msg.target.dispatchMessage(msg);
                dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
            } finally {
                if (traceTag != 0) {
                    Trace.traceEnd(traceTag);
                }
            }
            // 省略部分代碼。。。
			// 釋放消息所佔用的資源
            msg.recycleUnchecked();
        }
    }
    
    // 在Looper.loop()中調用了MessageQueue#next()源碼如下
    Message next() {
        // 省略部分的代碼。。。
        for (;;) {
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

			// nativePollOnce方法在native層,若是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;
                // 從隊列裏面取出消息,如果消息爲空的話,nextPollTimeoutMillis = -1,則會阻塞線程,此時消息隊列進入等待的狀態
                if (msg != null && msg.target == null) {
                    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 {
                    // 沒有消息的時候
                    nextPollTimeoutMillis = -1;
                }

               // 省略部分代碼。。。

            // While calling an idle handler, a new message could have been delivered
            // so go back and look again for a pending message without waiting.
            nextPollTimeoutMillis = 0;
        }
    }

當消息從Looper.loop()中被取出就會分調用了相對應的Handler#dispatchMessage()傳遞消息

	// Handler#dispatchMessage的源碼如下,在Looper.loop()中被調用
	public void dispatchMessage(Message msg) {
		// 先判斷了當前的消息類型是否Handler.post()時使用Runnable
        if (msg.callback != null) {
        	// 如果是傳入的Runnable則調用此方法,會調用Runnable.run()
            handleCallback(msg);
        } else {
            if (mCallback != null) {
            	// 如果在創建Handler時候傳入自定義Callback,則會調用此方法,並且可以限定Handler#handleMessage()是否執行
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            // 如果都沒有則調用Handler#handleMessage()方法
            handleMessage(msg);
        }
    }

到此整個的Handler機制和源碼也分析得差不多了!!!
字比較多,寫得好累

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