Handler中的IdleHandler

1.1 IdleHandler 基本狀況

IdleHandler 能夠用來提高性能,主要用在咱們但願可以在當前線程 消息隊列空閒時 作些事情(例如UI線程在顯示完成後,若是線程空閒咱們就能夠提早準備其餘內容)的狀況下,不過最好不要作耗時操做。java

IdleHandler 位於 MessageQueue 類中的一個靜態接口,以下:數組

MessageQueue#IdleHandler
class MessageQueue{
	...
	/**
     * Callback interface for discovering when a thread is going to block
     * waiting for more messages.
     *
	// 能夠理解爲消息暫時處理完的適合回調的
    public static interface IdleHandler {
        /**
         * Called when the message queue has run out of messages and will now
         * wait for more.  Return true to keep your idle handler active, false
         * to have it removed.  This may be called if there are still messages
         * pending in the queue, but they are all scheduled to be dispatched
         * after the current time.
         */
         //返回true就是單次回調後不刪除,下次進入空閒時繼續回調該方法,false 只回調單次執行完以後會移除
        boolean queueIdle();
    }
    
   //判斷當前隊列是否是空閒的,輔助方法
   public boolean isIdle() {
        synchronized (this) {
            final long now = SystemClock.uptimeMillis();
            return mMessages == null || now < mMessages.when;
        }
    }

  //添加一個IdleHandler 到空閒隊列中,ArrayList 存儲
   public void addIdleHandler(@NonNull IdleHandler handler) {
        if (handler == null) {
            throw new NullPointerException("Can't add a null IdleHandler");
        }
        synchronized (this) {
            mIdleHandlers.add(handler);
        }
    }
	// 刪除一個IdleHandler 
	public void removeIdleHandler(@NonNull IdleHandler handler) {
        synchronized (this) {
            mIdleHandlers.remove(handler);
        }
    }

	//message 的獲取下一條消息
    Message next() {
        ...
        int pendingIdleHandlerCount = -1; // -1 only during first iteration
        int nextPollTimeoutMillis = 0;
        for (;;) {//循環獲取下一條消息
            if (nextPollTimeoutMillis != 0) {
                Binder.flushPendingCommands();
            }

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

                // Process the quit message now that all pending messages have been handled.
                if (mQuitting) {
                    dispose();
                    return null;
                }

                // If first time idle, then get the number of idlers to run.
                // Idle handles only run if the queue is empty or if the first message
                // in the queue (possibly a barrier) is due to be handled in the future.
                if (pendingIdleHandlerCount < 0
                        && (mMessages == null || now < mMessages.when)) {
                    pendingIdleHandlerCount = mIdleHandlers.size();
                }
                //表示沒有設置idle handler 去運行,就阻塞
                if (pendingIdleHandlerCount <= 0) {
                    // No idle handlers to run.  Loop and wait some more.
                    mBlocked = true;
                    continue;
                }
				//設置長度,最小長度是4
                if (mPendingIdleHandlers == null) {
                    mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
                }
                //將集合轉化爲數組
                mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
            }

            // Run the idle handlers.
            // We only ever reach this code block during the first iteration.
            //循環遍歷這個空閒隊列數組
            for (int i = 0; i < pendingIdleHandlerCount; i++) {
                final IdleHandler idler = mPendingIdleHandlers[i];
                mPendingIdleHandlers[i] = null; // release the reference to the handler

                boolean keep = false;
                try {
                    //回調取出返回值
                    keep = idler.queueIdle();
                } catch (Throwable t) {
                    Log.wtf(TAG, "IdleHandler threw exception", t);
                }
				//這裏看到了吧,若是是返回false, 那就進去了,執行操做後就從集合中remove了
                if (!keep) {
                    synchronized (this) {
                        mIdleHandlers.remove(idler);
                    }
                }
            }
		....
        }
    }
    ...
}
複製代碼

1.2 使用場景

Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
            @Override
            public boolean queueIdle() {
                //這裏作一些操做
                Log.i("xx","addIdleHandler invoked..."+iv.getWidth() + "::"+iv.getHeight());

                return false;
            }
});
複製代碼

我記得以前咱們想要獲取xml中某個控件的widthheight 時,在 onCreate 方法中直接獲取,會獲取到是 0 , 由於這個 view 還未繪製完成,因此獲取不到,當時的解決方案我記得是使用 Handler 發送一個延時消息獲取,如今有更好的方式實現了,那就是經過 IdleHandler, 如上面代碼所示。 固然還能夠作一些其它預處理的簡單操做。async

IdleHandler 你明白了嗎?歡迎你們留言討論。ide

相關文章
相關標籤/搜索