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);
}
}
}
....
}
}
...
}
複製代碼
Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
@Override
public boolean queueIdle() {
//這裏作一些操做
Log.i("xx","addIdleHandler invoked..."+iv.getWidth() + "::"+iv.getHeight());
return false;
}
});
複製代碼
我記得以前咱們想要獲取xml中某個控件的
width
和height
時,在onCreate
方法中直接獲取,會獲取到是 0 , 由於這個view
還未繪製完成,因此獲取不到,當時的解決方案我記得是使用Handler
發送一個延時消息獲取,如今有更好的方式實現了,那就是經過IdleHandler
, 如上面代碼所示。 固然還能夠作一些其它預處理的簡單操做。async
IdleHandler
你明白了嗎?歡迎你們留言討論。ide