[TOC]

概述

Handler消息机制我们都不陌生,在日常开发中不可避免地要涉及这方面的内容。从开发的角度来说,Handler是Android消息机制的上层接口,这使得在开发过程中只需要和Handler交互即可。Handler的使用过程很简单,通过它可以轻松地将一个任务切换到Handler所在的线程中去执行。

Handler是什么

很多时候,我们都认为Handler的作用是更新UI。其实这个认识是错误的,至少是非常局限的一个认识,Handler的中文意思是处理器、处理者的意思。所以其实跟更新UI本质上没有什么关系。其实Handler更应该理解为:绑定特定线程的消息处理器。

什么叫绑定特定线程? 我们可以看一下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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
  // 代码位于:/frameworks/base/core/java/android/os/Handler.java
/**
* 默认无参构造函数将此处理程序与当前线程的{@link Looper}进行绑定。
* 如果此线程没有Looper,则此Handler将无法接收消息,因此将引发异常。
*
*/
@Deprecated
public Handler() {
this(null, false);
}

/**
* 构造函数将此处理程序与当前线程的{@link Looper}关联,并采用一个回调接口,您可以在其中处理消息。
* 如果此线程没有Looper,则此Handler将无法接收消息,因此将引发异常。
* @param callback 用于处理消息的回调接口
*/
@Deprecated
public Handler(@Nullable Callback callback) {
this(callback, false);
}

/**
* 传入looper对象的构造函数.我们自己传入
* @param looper The looper, must not be null.
* 传入looper对象的构造函数
* @param looper The looper, must not be null.
*/
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}

/**
*
*/
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}

/**
*
* @hide
*/
@UnsupportedAppUsage
public Handler(boolean async) {
this(null, async);
}

/**
*
* @hide
*/
public Handler(@Nullable Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class<? extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
// 获取当前线程的looper对象
mLooper = Looper.myLooper();
// looper为空的异异常处理.说明Handler对象必须要绑定一个looper对象
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
// 获取Looper对象里面的创建的MessageQueue
mQueue = mLooper.mQueue;
// 入参传入的callback
mCallback = callback;
// 判断当前Handler是个异步消息,还是同步消息Handler
mAsynchronous = async;
}

/**
* @hide
*/
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

通过Looper.myLooper()获取了当前线程保存的Looper实例,然后在19行又获取了这个Looper实例中保存的MessageQueue(消息队列),这样就保证了handler的实例与我们Looper实例中MessageQueue关联上了。

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
// 代码位于:/frameworks/base/core/java/android/os/Handler.java
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}
public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r), uptimeMillis);
}
public final boolean postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
public final boolean postDelayed(Runnable r, int what, long delayMillis) {
return sendMessageDelayed(getPostMessage(r).setWhat(what), delayMillis);
}
public final boolean postDelayed(@NonNull Runnable r, @Nullable Object token, long delayMillis) {
return sendMessageDelayed(getPostMessage(r, token), delayMillis);
}
public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
return sendMessageAtFrontOfQueue(getPostMessage(r));
}
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}
public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}
public final boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
// 使用Handler来发送异步消息
if (delayMillis < 0) {
delayMillis = 0;
}
// 其实是在未来某个时间点类处理这个消息
// 返回系统启动到现在的毫秒数,不包含休眠时间。
// 就是说统计系统启动到现在的非休眠期时间+delayMillis
return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);
}
public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
// 取得从Looper对象中取得MessageQueue
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消息入队列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* Handler进行发送消息之后,最终消息会添加到这个消息队列中。 enqueueMessage中首先为msg.target赋值为this,
* Looper的loop方法会取出每个msg然后交给msg,target.dispatchMessage(msg)去处理消息也就是把当前的handler作为msg的target属性。
* 最终会调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。
* 在一定的异步事件之内在交还给这个Handler处理
*
* @param queue Handler进行sendMsg的时候传入的消息实体
* @param msg
* @param uptimeMillis 消息的执行时机
* @return
*/
private boolean enqueueMessage(@NonNull MessageQueue queue, @NonNull Message msg, long uptimeMillis) {
// 为当前消息msg添加target。 这个target其实就是这个handler对象
// 所以我们想到之前在Looper的对象在loop()方法里面调用
msg.target = this;
msg.workSourceUid = ThreadLocalWorkSource.getUid();
// 判断当前Handler对象是同步消息Handler 还是异步消息Handler
if (mAsynchronous) {
msg.setAsynchronous(true);
}
// 添加消息队列中
return queue.enqueueMessage(msg, uptimeMillis);
}

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
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
	// 代码位于:/frameworks/base/core/java/android/os/MessageQueue.java
/**
* Handler进行发送消息之后,最终消息会添加到这个消息队列中。 enqueueMessage中首先为msg.target赋值为this,
*
* @param msg
* @param when
* @return
*/
boolean enqueueMessage(Message msg, long when) {
// 标记Handler发送的消息的Handler。这个直接影响着将来消息要交给谁执行
// 所以不能为空
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.");
}
// 如果调用了MessageQueue的quit方法,那么mQuitting是为true
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;
// mMessages 是真正的消息队列的单链表结果
Message p = mMessages;
// 判断是否触发消息队列遍历的唤醒。默认为false
boolean needWake;
// p是消息队列的头部
// 如果消息队列为空,或者这个消息是立即执行。或者之前队列的第一个消息事件也比当前的msg要迟
// 则这个时候这个消息就要入队列。并且是加入到消息队列的头部
if (p == null || when == 0 || when < p.when) {
// New head, wake up the event queue if blocked.
msg.next = p;
mMessages = msg;
// 是否需要唤醒。主要看当前消息队列是否已经阻塞了。如果已经block了。则就需要进行唤醒
// 因为消息队列的头部已经有消息需要处理了。所以需要唤醒啊
// TODO 这里我们可以思考一下什么时候会在进行阻塞消息处理呢
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.
// 如果待加入的消息不添加到消息队列的头部。而是在消息队列的尾部或者中间
// 那么需要唤醒就看:
// 1、是否之前阻塞过。
// 2、并且消息队列的头部如果是一个屏障消息。而此消息是一个同步消息
needWake = mBlocked && p.target == null && msg.isAsynchronous();
Message prev;
// 这是一个死循环,这个死循环是进行遍历这个消息队列。然后看这个消息插入到哪里比较合适
for (;;) {
// 消息队列的双指针遍历。
prev = p;
p = p.next;
if (p == null || when < p.when) {
break;
}
// 这个地方有意思。如果上面的needWake我们已经设置为true.
// 但是我们遍历插入消息的队列的是否。发现这个消息之前还有同步消息
// 那我们其实不需要唤醒的(其实就是已经被唤醒了)
if (needWake && p.isAsynchronous()) {
needWake = false;
}
}
// 找到消息可以插入的对应为。进行指针引用的重新连接。插入我们的消息
msg.next = p; // invariant: p == prev.next
prev.next = msg;
}
// 如果需要唤醒。我们就执行Native的方法。进行消息队列的唤醒
// We can assume mPtr != 0 because mQuitting is false.
if (needWake) {
nativeWake(mPtr);
}
}
return true;
}

enqueueMessage中首先为msg.target赋值为this,【如果大家还记得Looper的loop方法会取出每个msg然后交给msg,target.dispatchMessage(msg)去处理消息】,也就是把当前的handler作为msg的target属性。最终会调用queue的enqueueMessage的方法,也就是说handler发出的消息,最终会保存到消息队列中去。

现在已经很清楚了Looper会调用prepare()和loop()方法,在当前执行的线程中保存一个Looper实例,这个实例会保存一个MessageQueue对象,然后当前线程进入一个无限循环中去,不断从MessageQueue中读取Handler发来的消息。然后再回调创建这个消息的handler中的dispathMessage方法,下面我们赶快去看一看这个方法:

1
2
3
4
5
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}

我们子类必须实现这个类的handleMessage来进行消息的处理。

可以看到,调用了handleMessage方法,下面我们去看这个方法:

看到这个地方我们就很熟悉了。这里调用了handleMessage()可以看到这是一个空方法,为什么呢,因为消息的最终回调是由我们控制的,我们在创建handler的时候都是复写handleMessage方法,然后根据msg.what进行消息处理。

到此,这个流程已经解释完毕,让我们首先总结一下

1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,否则会进行报错。所以MessageQueue在一个线程中也是只会存在一个。

2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。

3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。

4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。

5、在构造Handler实例时,我们会重写handleMessage方法,也就是msg.target.dispatchMessage(msg)最终调用的方法。

主线程的Handler的Looper对象

好了,总结完成。大家可能还会问,那么在Activity中,我们并没有显示的调用Looper.prepare()和Looper.loop()方法,为啥Handler可以成功创建呢?

这是因为在Activity的启动代码中,已经在当前UI线程调用了Looper.prepare()和Looper.loop()方法。

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
	// 代码位于:/frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// Install selective syscall interception
// 安装选择性系统拦截
AndroidOs.install();

// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);

Environment.initForCurrentUser();
// Make sure TrustedCertificateStore looks in the right place for CA
// certificates
final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);

// Call per-process mainline module initialization.
initializeMainlineModules();
Process.setArgV0("<pre-initialized>");
// 初始化主线程功能的Looper
// 步骤一:Looper.prepareMainLooper()初始化主线程(UI)的Lopper对象
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command
// line.
// It will be in the format "seq=114"
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的对象
// 这个地方就是实例化ActivityThread
ActivityThread thread = new ActivityThread();
//
thread.attach(false, startSeq);

// 获取主线程的Handler对象
// 步骤二:同时在这个主线程获取sMainThreadHandler
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);
// 执行Looper对象的loop方法,开始执行消息的循环
// 步骤三: 调用Main主线程里面的loop方法
Looper.loop();
// 我们可以看到。在这个main函数的最后是抛出异常。所以这行的代码其实是永远也不会执行的
// 不会执行的原因就是 Looper.loop();里面其实是一个死循环。而这个死循环是永远不会退出。且不会造成卡死
throw new RuntimeException("Main thread loop unexpectedly exited");
}