android addIdleHandler 空闲线程 源码分析


描述

在项目中偶然看到其他人有在用

1
2
3
4
5
6
7
8
Looper.myQueue().addIdleHandler(new IdleHandler() {

@Override
public boolean queueIdle() {
...
}

}

之前一直不知道这么写是怎么回事, 今天特意研究了一下源码, 搞清楚了IdleHandler的机制.


源码分析

我们先来看下IdleHandler的add跟remove方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/**
* 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.
*/

boolean queueIdle();
}

/**
* Add a new {@link IdleHandler} to this message queue. This may be
* removed automatically for you by returning false from
* {@link IdleHandler#queueIdle IdleHandler.queueIdle()} when it is
* invoked, or explicitly removing it with {@link #removeIdleHandler}.
*
* <p>This method is safe to call from any thread.
*
* @param handler The IdleHandler to be added.
*/

public void addIdleHandler(@NonNull IdleHandler handler) {
if (handler == null) {
throw new NullPointerException("Can't add a null IdleHandler");
}
synchronized (this) {
mIdleHandlers.add(handler);
}
}

/**
* Remove an {@link IdleHandler} from the queue that was previously added
* with {@link #addIdleHandler}. If the given object is not currently
* in the idle list, nothing is done.
*
* <p>This method is safe to call from any thread.
*
* @param handler The IdleHandler to be removed.
*/

public void removeIdleHandler(@NonNull IdleHandler handler) {
synchronized (this) {
mIdleHandlers.remove(handler);
}
}

IdleHandler接口表示当MessageQueue发现当前没有更多消息可以处理的时候, 则顺便干点别的事情的callback函数(即如果发现idle了,
那就找点别的事干). callback函数有个boolean的返回值, 表示是否keep. 如果返回false, 则它会在调用完毕之后从mIdleHandlers中移除.

接下来看MessageQueue的核心方法—next()方法, 源码如下, 相关说明写在注释中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
Message next() {
// Return here if the message loop has already quit and been disposed.
// This can happen if the application tries to restart a looper after
// quit
// which is not supported.
final long ptr = mPtr;
if (ptr == 0) {
return null;
}

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.
// 这里执行的操作是忽略所有的同步消息, 知道找出queue中的异步消息
// 我理解是这个的同步消息会造成线程的阻塞, 所以忽略同步的消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
// 走到这一步, 有两种可能,
// 一种是遍历到队尾没有发现异步消息,
// 另一种是找到queue中的第一个异步消息
if (msg != null) {
// 找到queue中的第一个异步消息
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.
// 当前消息到达可以执行的时间, 直接返回这个msg
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.
// 如果queue中没有msg, 或者msg没到可执行的时间,
// 那么现在线程就处于空闲时间了, 可以执行IdleHandler了
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
// pendingIdleHandlerCount在进入for循环之前是被初始化为-1的
// 并且没有更多地消息要进行处理
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
// 如果没有IdleHandler要进行处理, 则直接进入下次循环
mBlocked = true;
continue;
}

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.
// 退出同步块, 接下来就可以执行IdleHandler的相关操作了
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);
}

if (!keep) {
// 如果之前addIdleHandler中返回为false,
// 就在执行完这个IdleHandler的callback之后, 将这个idler移除掉
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}

// Reset the idle handler count to 0 so we do not run them again.
// 全部执行完, 重新设置这个值为0, 以便下次可以再次执行
pendingIdleHandlerCount = 0;

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