Android 14 Handler 源码解析
2024-02-24 / 龙之叶   

前言

Handler 是一套 Android 消息传递机制。在多线程应用场景中,将子线程中需要更新 UI 的操作消息,传递到 UI 主线程,从而实现子线程通知 UI 更新最终实现异步消息处理。说白了是用于线程之间的通信。Handler主要有4个重要类:Handler、Message、MessageQueue、Looper。

Handler 简介

Handler主要有4个重要类:Handler、Message、MessageQueue、Looper。

  • Handler:负责消息的发送和处理,子线程中使用 sendMessage() 发送消息;在handleMessage()中处理。
  • Message:消息载体,里面存储这线程消息。
  • MessageQueue:消息队列,遵循先进先出的原则,存储着 sendMessage() 发送来的子线程消息。
  • Looper:消息循环器,负责从 MessageQueue 中循环取消息,再将取出的消息分发给 handleMessage(),来处理消息。

Handler 源码

了解 Handler,首先我们要了解 Handler 从消息发送到消息处理这整个流程,下面将分析这一流程,并回答下面几个问题:

  1. 一个线程有几个Handler?
  2. 一个线程有几个Looper?如何保证?
  3. Handler 内存泄漏原因?为什么其他的内部分没有过这个问题?
  4. 为何主线程可以 new Handler?如果想要在子线程中 new Handler 要做些什么准备?
  5. 子线程中的维护的 looper,消息队列无消息的时候处理方案是什么?有什么用?
  6. 既然可以存在多个 Handler 往 MessageQueue 中添加数据(发消息时,各个handler 可能处于不同的线程),那么它内部是如何确保线程安全的?
  7. 我们使用 Message 时应如何创建它?
  8. 使用 Handler 的 postDelay 后,消息队列会有什么变化?
  9. Looper 死循环为什么不会导致应用卡死(ANR)?

Handler

Handler 负责消息的发送和处理,该类中通过 sendXXX、postXXX等方法发送消息,共有14个这样的方法。而在 handleMessage() 中处理收到的消息。这里以 sendMessage(Message msg) 方法为例进行源码分析。
frameworks/base/core/java/android/os/Handler.java

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
public class Handler {
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
if (delayMillis < 0) {
delayMillis = 0;
}
// 第二的参数代表执行的时间,为:系统当前时间+延迟的时间
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
return enqueueMessage(queue, msg, uptimeMillis);
}
// 不管使用什么方法发送消息,都会调到 Handler#enqueueMessage()
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
// 把当前对象赋给msg.target,这样 Message 就持有了 Handler
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 调用 MessageQueue#enqueueMessage() 往消息队列添加消息。
return queue.enqueueMessage(msg, uptimeMillis);
}
}

MessageQueue

enqueueMessage 里面其实是一个优先级队列,将收到消息根据执行的时间 when 进行做排序处理。
frameworks/base/core/java/android/os/MessageQueue.java

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
public final class MessageQueue {
boolean enqueueMessage(Message msg, long when) {
if (msg.target == null) {
throw new IllegalArgumentException("Message must have a target.");
}
synchronized (this) {
if (msg.isInUse()) {
throw new IllegalStateException(msg + " This message is already in use.");
}
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;
// 如果是0,则放在最前面
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;
// 对单链表轮询,根据 when 进行排序插入消息。
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;
}
}

到这里发消息基本完成,后面看如何取消息。
next() 中返回一个 Message。
frameworks/base/core/java/android/os/MessageQueue.java

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
public final class MessageQueue {
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();
}
// nextPollTimeoutMillis :-1 表示无限等待,直到有事件为止;0 表示立即执行;其他数字表示等待多时毫秒。
// linux 层休眠等待,
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 { // 到了可以执行的时间,则把消息 return 出去。
// 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();
}
if (pendingIdleHandlerCount <= 0) {
// No idle handlers to run. Loop and wait some more.
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.
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);
}
}
}
// Reset the idle handler count to 0 so we do not run them again.
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;
}
}
}

到此,消息取出来了,但是谁取的呢?这就涉及到另一个重要的类 Looper

Looper

Looper.loop() 里面会有个for循环,且是个死循环,会不断的调用 MessageQueue#next() 方法。
frameworks/base/core/java/android/os/Looper.java

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
public final class Looper {
// 初始化Looper
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { // 如果该线程有 Looper,则抛出一个异常。
throw new RuntimeException("Only one Looper may be created per thread");
}
// 这里使用了 ThreadLocal,保证了一个线程只有一个Looper。
sThreadLocal.set(new Looper(quitAllowed));
}
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
if (me.mInLoop) {
Slog.w(TAG, "Loop again would have the queued messages be executed"
+ " before this one completed.");
}
me.mInLoop = true;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
// Allow overriding a threshold with a system prop. e.g.
// adb shell 'setprop log.looper.1000.main.slow 1 && stop && start'
final int thresholdOverride =
SystemProperties.getInt("log.looper."
+ Process.myUid() + "."
+ Thread.currentThread().getName()
+ ".slow", 0);
me.mSlowDeliveryDetected = false;
for (;;) { // 死循环
// 不断地调用mQueue.next()
if (!loopOnce(me, ident, thresholdOverride)) {
return;
}
}
}
private static boolean loopOnce(final Looper me,
final long ident, final int thresholdOverride) {
// 这里如果此时队列中没有消息或队列中,第一个节点还没到可以执行的时刻,则会进入等待,block 状态。
// 会一直在这等,该等待是Linux层做的,在 mQueue.next()中
Message msg = me.mQueue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return false;
}
// This must be in a local variable, in case a UI event sets the logger
final Printer logging = me.mLogging;
// Make sure the observer won't change while processing a transaction.
final Observer observer = sObserver;
final long traceTag = me.mTraceTag;
long slowDispatchThresholdMs = me.mSlowDispatchThresholdMs;
long slowDeliveryThresholdMs = me.mSlowDeliveryThresholdMs;
if (thresholdOverride > 0) {
slowDispatchThresholdMs = thresholdOverride;
slowDeliveryThresholdMs = thresholdOverride;
}
final boolean logSlowDelivery = (slowDeliveryThresholdMs > 0) && (msg.when > 0);
final boolean logSlowDispatch = (slowDispatchThresholdMs > 0);
final boolean needStartTime = logSlowDelivery || logSlowDispatch;
final boolean needEndTime = logSlowDispatch;
if (traceTag != 0 && Trace.isTagEnabled(traceTag)) {
Trace.traceBegin(traceTag, msg.target.getTraceName(msg));
}
final long dispatchStart = needStartTime ? SystemClock.uptimeMillis() : 0;
final long dispatchEnd;
Object token = null;
if (observer != null) {
token = observer.messageDispatchStarting();
}
long origWorkSource = ThreadLocalWorkSource.setUid(msg.workSourceUid);
try {
// 获取到消息后,就会调用 msg.target.dispatchMessage(msg),即回调 handler#dispatchMessage(msg)
// msg.target 为 handler对象
msg.target.dispatchMessage(msg);
if (observer != null) {
observer.messageDispatched(token, msg);
}
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} catch (Exception exception) {
if (observer != null) {
observer.dispatchingThrewException(token, msg, exception);
}
throw exception;
} finally {
ThreadLocalWorkSource.restore(origWorkSource);
if (traceTag != 0) {
Trace.traceEnd(traceTag);
}
}
if (logSlowDelivery) {
if (me.mSlowDeliveryDetected) {
if ((dispatchStart - msg.when) <= 10) {
Slog.w(TAG, "Drained");
me.mSlowDeliveryDetected = false;
}
} else {
if (showSlowLog(slowDeliveryThresholdMs, msg.when, dispatchStart, "delivery",
msg)) {
// Once we write a slow delivery log, suppress until the queue drains.
me.mSlowDeliveryDetected = true;
}
}
}
if (logSlowDispatch) {
showSlowLog(slowDispatchThresholdMs, dispatchStart, dispatchEnd, "dispatch", msg);
}
if (logging != null) {
logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
}
// Make sure that during the course of dispatching the
// identity of the thread wasn't corrupted.
final long newIdent = Binder.clearCallingIdentity();
if (ident != newIdent) {
Log.wtf(TAG, "Thread identity changed from 0x"
+ Long.toHexString(ident) + " to 0x"
+ Long.toHexString(newIdent) + " while dispatching to "
+ msg.target.getClass().getName() + " "
+ msg.callback + " what=" + msg.what);
}
msg.recycleUnchecked();
return true;
}
}

当获取到消息时,回调用 msg.target.dispatchMessage(msg) 即 **handler#dispatchMessage(msg)**,在 dispatchMessage(msg) 中再回调 handleMessage(msg) ,这样就收到消息。至此发消息、收消息整个流程结束。
下面回答上述的问题。

1.一个线程有几个Handler?
答:那个,new 多少就有多少。

2.一个线程有几个Looper?如何保证?
答:一个,在初始化时,使用了 ThreadLocal ,而 ThreadLocal 是一个 <key,value> 这种形式的变量,类似 hashMap。它的 key 是当前线程,value 是 Looper。
下方为对应源码分析:

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
// 初始化Looper 
public static void prepare() {
prepare(true);
}
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) { // 如果该线程有 Looper,则抛出一个异常。
throw new RuntimeException("Only one Looper may be created per thread");
}
// 这里使用了 ThreadLocal,保证了一个线程只有一个Looper。
sThreadLocal.set(new Looper(quitAllowed));
}
// ThreadLocal 的 set() 方法
public void set(T value) {
Thread t = Thread.currentThread(); // 当前线程
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
// ThreadLocal 的 get()方法,
public T get() {
Thread t = Thread.currentThread(); // 当前线程
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}

3.Handler 内存泄漏原因?为什么其他的内部分没有过这个问题?
出现内存泄漏的情况:Activity 销毁时,存在待处理的消息。例如:发送一个delay(延迟消息) 2s,在2s内销毁界面。
答:Handler 持有 Activity 的上下文,而 MessageQueue 持有 Message,Message 又持有 Handler;只有当这消息被处理时,才会去销毁对应的 Handler ,Handler 被销毁了,才会去销毁持有的上下文。而其他内部类,例如:RecyclerView 的 ViewHolder,不会产生内存泄漏,因为它没有被其它地方持有该内部类。
frameworks/base/core/java/android/os/Handler.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Handler {
// 不管使用什么方法发送消息,都会调到 Handler#enqueueMessage()
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg,
long uptimeMillis) {
// 把当前对象赋给msg.target,这样 Message 就持有了 Handler
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 调用 MessageQueue#enqueueMessage() 往消息队列添加消息。
return queue.enqueueMessage(msg, uptimeMillis);
}
}

4.为何主线程可以 new Handler?如果想要在子线程中 new Handler 要做些什么准备?
答:主线程在创建时,系统 ActivityThread 就已经创建好了。在子线程中 new Handler 需想初始化 Looper(Looper.prepare()),并启动 loop(Looper.loop())
frameworks/base/core/java/android/app/ActivityThread.java

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
public static void main(String[] args) {
// 省略部分代码......
Looper.prepareMainLooper();
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
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);
/// M: ANR Debug Mechanism
mAnrAppManager.setMessageLogger(Looper.myLooper());
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}

5.子线程中的维护的 looper,消息队列无消息的时候处理方案是什么?有什么用?
答:在适当地方调用 Looper.quitSafely();安全地退出 looper。 等所有剩余的消息处理完毕后立即终止。但是,在 loop 循环终止之前,将不会在收到消息。在要求循环程序退出后,任何向队列发送消息的尝试都将失败。

6.既然可以存在多个 Handler 往 MessageQueue 中添加数据(发消息时,各个handler 可能处于不同的线程),那么它内部是如何确保线程安全的?
答:在 MessageQueue#enqueueMessage、MessageQueue#next() 中的代码块使用了 synchronized 修饰。则也会导致 handler 的 delay 消息的时间不完全的准确。

7.我们使用 Message 时应如何创建它?
答:obtain(),避免了每次去 new ,防止了内存抖动。

8.使用 Handler 的 postDelay 后,消息队列会有什么变化?
答:若此时消息队列为空,则不会立马执行(Delay 消息);当该消息添加进去时,MessageQueue#enqueueMessage 会 调用 nativeWake(mPtr) 唤醒消息队列,就会在 MessageQueue#next() 中,计算等待时间。

9.Looper 死循环为什么不会导致应用卡死(ANR)?
每一个事件都是一个 Message,因为所有事件都在Activity的生命周期里面,而主线程的所有代码都运行在 ActivityThread#main()中的 loop 里面。所以主线程的 loop 不能退出。
主线程唤醒的方式;
1、输入的事件;
2、Looper 添加消息;
输入事件:点击屏幕或按键按下,得到系统响应。
答:ANR是指在5s内没有响应输入事件(例如:按键按下、屏幕触摸),而输入的事件、Looper 添加消息都可以唤醒 Looper 里面的 block。Looper 死循环 与 ANR没有关系。

本文链接:
http://longzhiye.top/2024/02/24/2024-02-24/