运行机制包括
- Handler
消息处理
持有 Looper、MessageQueue 对象 - Message
消息实体,用于存放需要处理的数据
持有 Handler 对象 - MessageQueue
消息队列
持有 Message
已经发送的消息,存放在 MessageQueue 这个消息队列上,等在 Looper 取出 - Looper
消息循环体
持有 MeeageQueue
一直循环取消息,促使Handler 执行 handleMessage
Handler.postDelay 是准时的吗
不准时,因为内部有锁,有锁的地方就有竞争无法做到准时
如果保证一个线程只有一个Looper
1
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
静态变量保证只有一个 sThreadLocal
用 ThreadLocal 来保证每一个线程都有一个 Looper
Android中存在那么多Messager为什么没有产生内存抖动
MessagePool 存放头是,链表结构 message执行完后并没有释放,而是将message的内容置空添加到MessagePool,长度最大50
Looper
首先整个App程序的入口在 ActivityThread 的 main 方法中
1
2
3
4
5
6
7
public static void main(String[] args) {
...
Looper.prepareMainLooper();
Looper.loop();
...
}
Hanlder 机制流程
- Message obtain()
1 2 3 4 5 6 7 8 9 10 11 12 13
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; } } return new Message(); }
sPool 是一个Message 链表的头节点,当 Message 使用完的时候,就会添加到 sPool 链表头部,调用 obtain 从链表中取出头节点,如果链表为空创建新 Message
与之对应的 recycle() 调用了 recycleUnchecked()1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
void recycleUnchecked() { // Mark the message as in use while it remains in the recycled object pool. // Clear out all other details. flags = FLAG_IN_USE; what = 0; arg1 = 0; arg2 = 0; obj = null; replyTo = null; sendingUid = UID_NONE; workSourceUid = UID_NONE; when = 0; target = null; callback = null; data = null; synchronized (sPoolSync) { if (sPoolSize < MAX_POOL_SIZE) { next = sPool; sPool = this; sPoolSize++; } } }
- 创建 Handler()
Handler() 如果不指定 Looper 默认是当前线程的 Looper - 发送消息 handler.sendMessage(message) 最终会执行到 handler.enqueueMessage
1 2 3 4 5 6 7 8 9 10
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) { msg.target = this; msg.workSourceUid = ThreadLocalWorkSource.getUid(); if (mAsynchronous) { msg.setAsynchronous(true); } return queue.enqueueMessage(msg, uptimeMillis); }
- MessageQueue.enqueueMessage 将 Message 添加到 MessageQueue
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
boolean enqueueMessage(Message msg, long when) { ... synchronized (this) { ... 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. if (needWake) { nativeWake(mPtr); } } return true; }
由上述代码可知,如果是非延迟 Message 就插入到链表头部;如果是延迟消息就遍历列表根据执行时间插入到对应的位置。由插入规则可知,这是一个根据执行时间排序的链表
- 等待 Looper.loop 执行到 Message
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
public static void loop() { final Looper me = myLooper(); final MessageQueue queue = me.mQueue; for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; } ... msg.target.dispatchMessage(msg); ... msg.recycleUnchecked(); } }
由代码可知,这是一个循环,不断的从 MessageQueue.next() 中获取到 message 并交由 Handler 执行,执行完毕会调用 recycleUnchecked 将自己添加到回收池中
- MessageQueue.next() 获取 Message
if (msg == null) {return;} 这句代码意思是如果 msg 为 null 就会退出 Looper ,由前文可知如果主线程 Looper 退出,整个程序就会退出,显然不符合App的实际运行情况,也就是说主线程 msg 除非应用退出否则不可能为 null 。实际情况是所有线程的 Looper 除非主动退出,msg 都不会为 null 。 确保 msg 不为 null 的点在于 queue.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
Message next() { ... 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; // 如果msg.target == null 表示这是一个屏障消息,用于触发屏障机制,当触发屏障机制只会执行异步方法 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; msg.markInUse(); return msg; } } else { // No more messages. nextPollTimeoutMillis = -1; } ... } ... } }
- 内部也是一个无条件for (;;) 循环,只有在 Mssage 不为 null 的时候跳出循环,如果没有到执行时间就会一直循环。
- 一直检测循环肯定会浪费CPU资源,那是如何解决的呢,答案就是 nativePollOnce 方法
其中 nativePollOnce(ptr, nextPollTimeoutMillis) 是一个 native 方法,作用是释放CUP资原,阻塞线程 nextPollTimeoutMillis 毫秒;从代码可知,第一次循环的时候 nextPollTimeoutMillis 为0,是没有等待的,获取链表头部 mssage ,已知 MessageQueue 是根据执行时间排序的,所以头部最先执行。计算这个头部 Message 是否已经到了执行时间,如果已经到执行时间则直接返回。如果还没到执行时间则计算需要等待的时间 - 如果在等待时间的时候,插入了新的立即执行 Message 怎么办?
查看 MessageQueue.enqueueMessage() 内有一句 if (needWake) {nativeWake(mPtr);} ,在插入新 Message 时如果是同步 Message 会主动唤醒 - Message 可分为三种
- barrier message : taget 为 null
- 同步 message :就是我们平常用的 message
- 异步 message : isAsynchronous = true,异步 message 配合 barrier 可获得优先执行权
1 2 3 4 5 6 7
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()); }
这段代码的目的是:设置 Barrier 后优先执行异步 Message
- msg.target.dispatchMessage(msg); 调用 handler 的 dispatchMessage 处理 message
1 2 3 4 5 6 7 8 9 10 11 12
public void dispatchMessage(@NonNull Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } }
- 优先执行 message.callback
- 如果 message.callback 为 null,则执行 handler.mCallback
- 如果 handler 的 mCallback 为 null 或者 返回 false 才执行 handler.handleMessage(message)
Handler 消息屏障机制(这是Handler内部机制并没有对外开放,主要用来提高 View 绘制消息的优先级)
当 通过方法 mHandler.getLooper().getQueue().postSyncBarrier() 向 MessageQueue 发送一个 target 为 null 的 Mssager ,就是添加一个屏障 当 MessageQueue 的第一个消息为屏障消息时,这个时候会只处理异步消息,直到屏障消息被移除
1
2
3
4
5
6
7
8
9
10
11
12
13
@UnsupportedAppUsage
Message MessageQueue.next() {
//...
if (msg != null && msg.target == null) {//如果是消息屏障
//循环遍历消息,直到发现异步消息
do {
prevMsg = msg;
msg = msg.next;
} while (msg != null && !msg.isAsynchronous());
}
//...
}
如果没有移除消息屏障,MessageQueue.next() 不会获取到同步消息
MessageQueue.addIdleHandler(@NonNull IdleHandler handler)
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
Message next() {
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) {
// 上面代码已经分析过了,如果当前没有要执行的 Message 才会执行下面方法
// 没有要执行的Message,可能是MessageQueue 为空,也能是延迟消息未到执行时机
// 当没有消息要执行的时候,就会从 mIdleHandlers 取出回调并执行
if (pendingIdleHandlerCount < 0
&& (mMessages == null || now < mMessages.when)) {
pendingIdleHandlerCount = mIdleHandlers.size();
}
if (pendingIdleHandlerCount <= 0) {
// 当 mIdleHandlers 也为空的时候,变为阻塞状态
mBlocked = true;
continue;
}
// 从 mIdleHandlers 拷贝到 mPendingIdleHandlers
if (mPendingIdleHandlers == null) {
mPendingIdleHandlers = new IdleHandler[Math.max(pendingIdleHandlerCount, 4)];
}
mPendingIdleHandlers = mIdleHandlers.toArray(mPendingIdleHandlers);
}
// 遍历执行 mIdleHandlers
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) {
synchronized (this) {
mIdleHandlers.remove(idler);
}
}
}
pendingIdleHandlerCount = 0;
nextPollTimeoutMillis = 0;
}
}
dispatchMessage
1
2
3
4
5
6
7
8
9
10
11
12
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
总结:一共有三个地方可以处理 message ,具体逻辑请看上面代码。
Messager 空闲阻塞实现
Looper
nativePollOnce nativeWake
Native Looper
epoll
epoll_create 创建一个 epoll 的句柄。 epoll_ctl 事件注册函数,可以监听文件的指定状态的变化,比如可读性等状态变化 epoll_wait 等待事件的产生,可以设置超时时间。