Android 中的消息机制
Android 消息机制
为什么 Android 中的默认操作都在主线程,但是却没有导致阻塞、停止,应用程序仍然能够流畅地运行?
这就涉及到了 Android 中的运行机制,其实质是基于消息队列的形式运行在特定的线程中的。这个特定线程就是我们所说的主线程或 UI 线程(ActivityThread)。
![](https://img.haomeiwen.com/i1234624/38413fa876749427.png)
一个主线程拥有一个 Looper,一个 Looper 拥有一个 MessageQueue,而 MessageQueue 中包含多个 Handler 投递过来的 Message,并通过 Handler 循环地处理 Message。
Looper
Looper,暂且称其为“循环装置”吧。这个循环装置怎么来的呢?我们从 UI 线程的入口 ActivityThread 一探究竟。
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
首先,Looper 通过 prepare 方法创建一个 UI 线程唯一的 Looper 对象:
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
Looper 对象通过 ThreadLocal 保证一个线程同时只存在一个该对象的实例:
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
public final class Looper {
/*
* API Implementation Note:
*
* This class contains the code required to set up and manage an event loop
* based on MessageQueue. APIs that affect the state of the queue should be
* defined on MessageQueue or Handler rather than on Looper itself. For example,
* idle handlers and sync barriers are defined on the queue whereas preparing the
* thread, looping, and quitting are defined on the looper.
*/
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
}
Looper 创建完成后就开始了它辛勤的工作,Looper.loop() 方法就是在不断地、重复的从消息队列中取得消息,并完成消息的处理:
/**
* Run the message queue in this thread. Be sure to call
* {@link #quit()} to end the loop.
*/
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
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;
}
try {
msg.target.dispatchMessage(msg);
...
} finally {
...
}
}
...
}
myLooper() 方法的返回值就是刚刚通过 prepareMainLooper() 方法创建的 UI 线程中唯一的“循环装置” Looper:
/**
* Return the Looper object associated with the current thread. Returns
* null if the calling thread is not associated with a Looper.
*/
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
MessageQueue
上面的源码中,有一行关于 MessageQueue 的代码:
public static void loop() {
...
final MessageQueue queue = me.mQueue;
...
}
可见,MessageQueue 是从 Looper 中得到的,那么 MessageQueue 何时被创建的呢?
其实在 prepare Looper 的时候就已经创建了该 Looper 的唯一 MessageQueue 实例:
private static void prepare(boolean quitAllowed) {
...
sThreadLocal.set(new Looper(quitAllowed));
}
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
...
}
Message
回到之前的 loop() 方法中的相关代码,在 for 循环中有这样一行源码:
public static void loop() {
...
Message msg = queue.next(); // might block
...
}
可见,Looper 在不断地从消息队列中获取消息,获取消息成功后去处理消息:
public static void loop {
...
msg.target.dispatchMessage(msg);
...
}
Handler
每一条消息都有一个 target,而这个 target 就是 Handler 对象。我们通过以下代码发送的消息最终的 target 会被指定为当前 new 出来的 Handler,同时被该 Handler 处理:
new Handler().sendMessage(msg)
那么,当我们在 new 一个 Handler 的时候,Android 都帮我们做了什么呢?
public Handler(Callback callback, boolean async) {
...
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
...
}
通过以上代码我们了解到,Handler 将成员变量 mLooper 赋值了,而这个值就是当前创建 Handler 线程中的唯一的 Looper,如果是主线程创建的 Handler,那自然就是通过 prepareMainLooper() 方法创建的主线程 Looper。
如果想在子线程中创建 Handler,在该线程启动时必须初始化 Looper 对象,否则会抛出上述代码中的 RuntimeException 异常。在子线程中创建 Looper 的代码示例如下:
@Override
public void run() {
Looper.prepare();
synchronized (this) {
mLooper = Looper.myLooper();
notifyAll();
}
Looper.loop();
...
}
此时就可以在子线程中创建 Handler 了,当然也可以指定 Handler 的 Looper 对象:
new Handler(Looper.getMainLooper())
总结
通过上面的分析,再来看下文章开头提出的问题:
为什么 Android 中的默认操作都在主线程,但是却没有导致阻塞、停止,应用程序仍然能够流畅地运行?
其实,主线程在一开始就创建了一个 Looper 对象去做了一个死循环操作,一般情况下,程序永远也无法停止。其次,基于消息队列的机制使得程序可以流畅地运行,而不会出现阻塞的情况发生。
但是,为了保证 UI 的流畅性,一些耗时操作仍然需要在子线程中完成,UI 线程的串行循环只能处理短时间的响应事件,一旦出现耗时操作,必然会引发 ANR 等问题。
本文由
Fynn_ 原创,未经许可,不得转载!