Handler、Looper、MessageQueue消息机制原理
Android消息机制是安卓开发中非常重要的,在子线程中处理完I/O、网络请求,使用Handler切回到主线程处理。
1、Looper
Android Looper设计的非常巧妙,使用ThreadLocal实现这个特性。关于ThreadLocal参考另外一篇Thread和ThreadLocal。
1.1、主线程Looper
一个Application启动的时候就会开启一个主Looper,因为比较特殊,所以可以在任何一个地方通过Looper.getMainLooper()方法获取到。来看看主线程中Looper的初始化,从ActivityThread中的main()静态方法启动一个应用:
public static void main(String[] args) {
AndroidOs.install();
...
Looper.prepareMainLooper();
...
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}主线程Looper已经在Application启动的时候初始化prepareMainLooper(),无需要开发者调用此方法,由框架负责调用初始化主线程Looper。
/**
* Initialize the current thread as a looper, marking it as an
* application's main looper. See also: {@link #prepare()}
*
* @deprecated The main looper for your application is created by the Android environment,
* so you should never need to call this function yourself.
*/
@Deprecated
public static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}主线程的sMainLooper在APP运行起来时必然已经初始化,
@UnsupportedAppUsage
private static Looper sMainLooper; // guarded by Looper.class所以提供了静态方法getMainLooper()可以在应用任何地方获取主线程Looper实例:
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}1.2、初始化Looper
其它子线程默认是没有Looper,如果需要先为所在线程准备一个Looper,使用prepare()静态方法。
/** Initialize the current thread as a looper.
* This gives you a chance to create handlers that then reference
* this looper, before actually starting the loop. Be sure to call
* {@link #loop()} after calling this method, and end it by calling
* {@link #quit()}.
*/
public static void prepare() {
prepare(true);
} 注意只能调用一次,不要重复在同一个线程中prepare(),如果线程已经有了一个Looper再次设置一个Looper会抛出异常。
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));
}prepare()方法给当前ThreadLocal设置Looper实例。
// sThreadLocal.get() will return null unless you've called prepare().
@UnsupportedAppUsage
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();Looper构造函数初始化一个Looper实例,设置给当前线程的sThreadLocal变量。无论设置给哪个ThreadLocal,最终都是set给当前Thread中的ThreadLocal对象副本。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}Looper内部持有一个MessageQueue对象mQueue,直接创建Handler的时候,Handler会通过ThreadLocal获取到当前线程的Looper,进而获取到Looper中的mQueue。
1.3、开启循环
开启Loop循环,在当前线程中运行消息队列。该方法里面有一个无限循环,有消息就通过msg.target.dispatchMessage(msg)发送给Handler处理。注意调用MessageQueue的next()方法获取队列中的Message,也可能阻塞吗,后面MessageQueue会说到。
①有消息:一直循环
②无消息:返回。但是注意,前面MessageQueue的next()方法没有消息也会一直阻塞,除非调用quit()方法,让MessageQueue停止循环,否则loop()也是不会走到return的。
/**
* 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) {
return;
}
try {
msg.target.dispatchMessage(msg);
}
...
msg.recycleUnchecked();
}
}1.4、退出Looper循环
注意一定要在线程退出的时候调用Looper的quit()方法,否则会造成内存泄漏。方法中还是通过调用MessageQueue的quit()方法退出,后面再看MessageQueue原理。
public void quit() {
mQueue.quit(false);
}2、MessageQueue
消息队列,但实际上是用链表实现的,并不真的是“队列”。MessageQueue结合Looper完成消息传递,普通开发工程师基本上用不到,但是还是需要对这个队列的实现原理有所了解的。
2.1、next()
最重要的一个方法就是next(),内部也有一个无限循环,会不断的从消息队列中取Message对象。
①有消息:返回消息。
②无消息:一直不断的循环;阻塞前面调用方法loop()。
Message next() {
...
final long ptr = mPtr;
if (ptr == 0) {
return null;
}
for (;;) {
...
Message msg = mMessages;
if (msg != null) {
if (now < msg.when) {
...
} else {
...
return msg;
}
}
if (mQuitting) {
dispose();
return null;
}
...
}
}2.2、enqueueMessage(Message msg, long when)
Handler发送的Message最终通过该方法,放入消息队列中。这里和链表插入有关,实现Message延迟的核心代码,详解见Handler消息延迟原理。
3、Handler
构造一个Handler,除了使用Looper还可以借助Callback。需要重写Handler中的handlerMessage()方法,处理不同的Message。
3.1、创建Handler
①主线程中可以直接创建Handler,开头已经知道主线程的Looper默认初始化的。
②如果在子线程中使用Handler,要么使用主线程的Looper:
Handler handler = new Handler(Looper.getMainLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
}
};要么必须先初始化所在子线程的Looper,开启Looper,才能创建子线程的Handler:
Looper.prepare();
Looper.loop();
Handler handler = new Handler(){
@Override
public void handleMessage(@NonNull Message msg) {
}
};否则之间创建Handler会奔溃报错:java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
Handler handler = new Handler();Handler构造方法:
public Handler() {
this(null, false);
}
public Handler(@Nullable Callback callback, boolean async) {
...
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;
...
}构造Handler的时候,就已经将内部的几个重要成员变量初始化:mLooper、mQueue。
3.2、sendMessage(Message msg)
发送消息,经过调用链跳转:sendMessage->sendMessageDelayed->sendMessageAtTime
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);
}3.3、enqueueMessage(...)
发送的消息最终是到了成员变量mQueue消息队列中。这里会将Message中的target设置为当前发送的Handler。
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);
}3.4、dispatchMessage(Message msg)
Looper在loop()方法中循环的时候,会将消息发送会Handler处理。
try {
msg.target.dispatchMessage(msg);
}分发消息:
public void dispatchMessage(@NonNull Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}3.5、handleMessage(Message msg)
到这里是不是发现很熟悉呢?没错,就是创建Handler的时候重写的handleMessage()方法,这个方法最终在Looper所在的线程loop()循环中被调用,通过Handler可以将子线程的数据传回主线程,更新UI。另见Handler中Callback的作用一文。
/**
* Subclasses must implement this to receive messages.
*/
public void handleMessage(@NonNull Message msg) {
}推荐博客:
Android 消息处理机制(Looper、Handler、MessageQueue,Message)
Android--异步消息处理机制(Handler、Looper、Message、MessageQueue)
Android Handler机制之Message的发送与取出


