Android-Handler

Android-Handler

1. Handler的实例化和初始化

Handler 在 Android 开发中还是相当相当常见的,其涉及到了很多 Android 和 Java 的数据结构。Handler 的源码并不复杂,原理也很有意思,常用的方法里实例化和初始化就占了很大一部分,消息 Message 的传递也占了很大一部分,本文主要也是分析这两点,剩下的用的不是太多,直接阅读源码也很快,在本文就不分析了。通过阅读 Handler 以及相关类的源码,可以深刻体会到 Android 的一些通用设计理念。

1.1 什么是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
/**
* A Handler allows you to send and process {@link Message} and Runnable
* objects associated with a thread's {@link MessageQueue}. Each Handler
* instance is associated with a single thread and that thread's message
* queue. When you create a new Handler, it is bound to the thread /
* message queue of the thread that is creating it -- from that point on,
* it will deliver messages and runnables to that message queue and execute
* them as they come out of the message queue.
*
* <p>There are two main uses for a Handler: (1) to schedule messages and
* runnables to be executed at some point in the future; and (2) to enqueue
* an action to be performed on a different thread than your own.
*
* <p>Scheduling messages is accomplished with the
* {@link #post}, {@link #postAtTime(Runnable, long)},
* {@link #postDelayed}, {@link #sendEmptyMessage},
* {@link #sendMessage}, {@link #sendMessageAtTime}, and
* {@link #sendMessageDelayed} methods. The <em>post</em> versions allow
* you to enqueue Runnable objects to be called by the message queue when
* they are received; the <em>sendMessage</em> versions allow you to enqueue
* a {@link Message} object containing a bundle of data that will be
* processed by the Handler's {@link #handleMessage} method (requiring that
* you implement a subclass of Handler).
*
* <p>When posting or sending to a Handler, you can either
* allow the item to be processed as soon as the message queue is ready
* to do so, or specify a delay before it gets processed or absolute time for
* it to be processed. The latter two allow you to implement timeouts,
* ticks, and other timing-based behavior.
*
* <p>When a
* process is created for your application, its main thread is dedicated to
* running a message queue that takes care of managing the top-level
* application objects (activities, broadcast receivers, etc) and any windows
* they create. You can create your own threads, and communicate back with
* the main application thread through a Handler. This is done by calling
* the same <em>post</em> or <em>sendMessage</em> methods as before, but from
* your new thread. The given Runnable or Message will then be scheduled
* in the Handler's message queue and processed when appropriate.
*/

大概翻译一下,这段注释基本也介绍清楚了 Handler 的工作流程:

  • Handler 允许你发送和处理和线程的 MessageQueue 相关联的 Message 和 Runnable 对象。每个 Handler 实例对象都只和一个线程以及该线程的消息队列。当创建一个 Handler 实例时,这个 Handler 会与线程以及这个线程创建的消息队列绑定,这之后,这个 Handler 会负责给 MessageQueue 传送 Message 和 Runnable,或者负责处理从 MessageQueue 中取出的 Message 和 Runnable。
  • Handler 有 2 个主要的用途:(1)给 Message 和 Runnable 安排一个未来执行的时间(可以是相差 0,表示立即执行);(2)将一个事务提交到另一个不同的线程处理。
  • Handler 通过 postpostAtTime(Runnable, long)postDelayedsendEmptyMessagesendMessagesendMessageAtTimesendMessageDelayed 方法调度 Message。post 方式允许发送一个 Runnable 对象并在被 MessageQueue 接收后调用。shendMessage 方式允许发送一个包括了一个 Bundle 形式的数据的 Message,并且在 Handler.handleMessage() 方法中处理(要求实现一个 Handler 的子类)。
  • 不论使用 post 还是 send 方式发送消息,都可以让这些消息在 MessageQueue 可用时立即处理,或者指定一个延时间隔来延迟处理,或者指定一个具体的处理事件。后面二者可以通过:延迟、具体时间、或其他基于时间的行为来实现。
  • 当 App 的进程被创建时,它的主线程则专门用来运行一个管理顶层应用对象的 MessageQueue,这些顶层应用对象可以是例如:Activity,BroadcastReceiver 等等,或是他们创建的其他 Windows。你可以创建自己的子线程,并通过 Handler 与主线程通信,只需要在子线程中调用上述的 send 类型或 post 类型的方法即可,发送的 Message 或 Runnable 将在 Handler 的 MessageQueue 合适的时候被调度和处理。

需要注意的几个重点:(1)Handler 可以用来发送消息也可以用来处理消息;(2)发送消息有两种类型的方式,处理消息可以跨进程;(3)Handler 的实例是和当前线程以及当前线程的 MessageQueue 绑定的;(4)MessageQueue 中维护的单链表只支持 Message 对象,因此 Runnable 是通过封装进 Message 来实现的。

1.2 Handler构造方法

Handler 内部有多个不同参数的构造方法,依次看看:

(1)无参默认构造方法

1
2
3
4
5
6
7
8
9
10
/**
* Default constructor associates this handler with the {@link Looper} for the
* current thread.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*/
public Handler() {
this(null, false);
}

该构造方法会使得 Handler 与当前线程的 Looper 关联,如果当前线程没有 Looper,则 Handler 将无法接收消息,从而抛出异常。

(2)1 个参数(Callback)的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Constructor associates this handler with the {@link Looper} for the
* current thread and takes a callback interface in which you can handle
* messages.
*
* If this thread does not have a looper, this handler won't be able to receive messages
* so an exception is thrown.
*
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(@Nullable Callback callback) {
this(callback, false);
}

和默认无参构造方法类似,只不过重写了接收消息后处理的回调方法 handleMessage

(3)1 个参数(async)的构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* Use the {@link Looper} for the current thread
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
@UnsupportedAppUsage
public Handler(boolean async) {
this(null, async);
}

和默认无参构造方法类似,只不过指定了通过这个 Handler 发送的消息为异步消息(Async)。

(4)以上第 1、2、3 种构造方法最终均调用了 2 个参数(Callback, async)的构造方法:

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
/**
* Use the {@link Looper} for the current thread with the specified callback interface
* and set whether the handler should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by {@link MessageQueue#enqueueSyncBarrier(long)}.
*
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @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());
}
}

mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

Looper.myLooper() 就是返回了当前线程中的 Looper 实例对象,如果当前线程不具备处理消息的功能,也即没有 Looper 实例,则返回 null,接下来也就是当存在 Looper 实例对象时,获取并绑定其消息队列 MessageQueue,处理事件的回调 Callback,以及设置是否异步 async。

(5)1 个参数(Looper)的构造方法

1
2
3
4
5
6
7
8
/**
* Use the provided {@link Looper} instead of the default one.
*
* @param looper The looper, must not be null.
*/
public Handler(@NonNull Looper looper) {
this(looper, null, false);
}

手动指定这个 Handler 需要绑定的线程,当我们需要从子线程更新 UI 时,通常会使用如下方法来实例化一个 Handler:

1
Handler handler = new Handler(Looper.getMainLooper());

这其实就是调用的这个构造方法,而 Looper.getMainLooper() 返回的就是主线程的 Looper 实例对象。

(6)2 个参数(Looper, Callback)的构造方法

1
2
3
4
5
6
7
8
9
10
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
*/
public Handler(@NonNull Looper looper, @Nullable Callback callback) {
this(looper, callback, false);
}

同时指定 Looper 和 Callback。

(7)以上第 5、6 种构造方法最终均调用了 3 个参数的构造方法:

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
/**
* Use the provided {@link Looper} instead of the default one and take a callback
* interface in which to handle messages. Also set whether the handler
* should be asynchronous.
*
* Handlers are synchronous by default unless this constructor is used to make
* one that is strictly asynchronous.
*
* Asynchronous messages represent interrupts or events that do not require global ordering
* with respect to synchronous messages. Asynchronous messages are not subject to
* the synchronization barriers introduced by conditions such as display vsync.
*
* @param looper The looper, must not be null.
* @param callback The callback interface in which to handle messages, or null.
* @param async If true, the handler calls {@link Message#setAsynchronous(boolean)} for
* each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
*
* @hide
*/
@UnsupportedAppUsage
public Handler(@NonNull Looper looper, @Nullable Callback callback, boolean async) {
mLooper = looper;
mQueue = looper.mQueue;
mCallback = callback;
mAsynchronous = async;
}

这个构造方法则是最详细的,可以同时指定 Looper,Callback,以及是否异步 async。

通过查看以上 7 种构造方法,可以总结出 Handler 的实例化过程:如果没有显式传入任何参数,则默认绑定当前线程的 Looper,使用默认 Callback,发送同步消息,否则按照对应显式传入的参数手动指定。


2. Handler发送Message

2.1 源码分析

在平时开发中 Handler 最主要的用途就是在子线程中更新 UI,两种方式:

  • send 方式,包括:

    • sendMessagesendEmptyMessage
    • sendMessageDelayedsendEmptyMessageDelayed
    • sendMessageAtTimesendEmptyMessageAtTime
    • sendMessageAtFrontOfQueue(比较特殊,会在后面详细讲解)
  • post 方式,包括:

    • post
    • postDelayed
    • postAtTime
    • postAtFrontOfQueue

其中,通过查看 post 方式的源码可以发现:

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
// 默认
public final boolean post(@NonNull Runnable r) {
return sendMessageDelayed(getPostMessage(r), 0);
}

// Delayed
public final boolean postDelayed(@NonNull Runnable r, long delayMillis) {
return sendMessageDelayed(getPostMessage(r), delayMillis);
}
/** @hide */
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);
}

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

// AtFrontOfQueue
public final boolean postAtFrontOfQueue(@NonNull Runnable r) {
return sendMessageAtFrontOfQueue(getPostMessage(r));
}

实际上 post 方式最终都是通过 send 方式实现的。再看一下各个 send 方式的源码:

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
public final boolean sendMessage(@NonNull Message msg) {
return sendMessageDelayed(msg, 0);
}

public final boolean sendEmptyMessage(int what) {
return sendEmptyMessageDelayed(what, 0);
}

public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageDelayed(msg, delayMillis);
}

public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
Message msg = Message.obtain();
msg.what = what;
return sendMessageAtTime(msg, uptimeMillis);
}

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

public final boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
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, 0);
}

在以上源码中可以看到一个参数:uptimeMillis,这个参数是从开机到当前时刻的时间间隔(毫秒,当设备处于睡眠时不计算),表示消息需要被处理时的时间,任意不同时刻获取到的该值都是不同的,uptimeMillis 越小表示消息越早处理。消息在添加到消息队列中时,是按照实际处理的时间从先到后按顺序排列的,并且除了 sendMessageAtFrontOfQueue 方法之外,其他 send 方式本质都是通过这一个方法发送的:sendMessageAtTime,而这两个方法最终都调用了 enqueueMessage,看看这个方法内部:

1
2
3
4
5
6
7
8
9
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);
}

这个方法每一句都说明了 Message 的一个性质:

  • msg.target = this; 这句把 Message 和 Handler 绑定在了一起。
  • msg.workSourceUid = ThreadLocalWorkSource.getUid(); 这句是获取到了当前线程的 Uid,也就是和当前线程绑定在了一起。
  • msg.setAsynchronous(true); 这句是设置为异步,if 也表示默认情况下的 Message 是同步的。

最后调用了 MessageQueue.enqueueMessage 方法把 Message 插入到消息队列中。

2.2 流程总结

通过以上源码分析,Handler 在发送一个消息后的流程也就清楚了:

  1. 接收一个 Message,并根据设置的延时,设置 Message 的 when
  2. 根据情况设置 Message 的类型,默认情况下为同步消息
  3. 将 Message 的 target 设置为自己
  4. 调用 MessageQueue 的 enqueueMessage 方法
  5. MessageQueue.enqueueMessage 方法中,根据 when 从小到大的顺序将 Message 插入到单链表对应位置
  6. 根据条件唤醒 Native 层的消息队列

3. Handler机制总结

通过分析 Handler 的实例化和初始化,以及 Handler 发送消息的流程,可以总结出 Handler 的工作机制:

  1. Handler 默认和当前线程以及当前线程的 MessageQueue 绑定,默认发送同步消息。
  2. 可以手动指定 Handler 的线程、重写接收消息后的回调方法 Callback.handleMessage()
  3. 可以手动指定发送的消息类型,但一个 Handler 只能发送一种消息,不能交替发送。
  4. Handler 所在线程由实例化时的 Looper 有关,且只能接收到与之绑定的线程中的消息,如果线程不具备处理消息的功能,则 Handler 无法接收消息且会抛出异常。
  5. Handler 有两种发送消息的方式,但本质上都是 send 方式。
  6. Handler 可以发送 Message,也可以发送 Runnable,但由于 MessageQueue 维护的单链表元素是 Message,因此 Runnable 实际上是封装在 message 中的。