详细的介绍可以看洋神的 Android 异步消息处理机制 让你深入理解 Looper、Handler、Message三者关系,我在这里只是简单的回顾一下。
Looper.prepare() 创建线程相关的 Looper 和 MessageQueue,Handler 将消息放入 MessageQueue,Looper.loop() 循环读取 Message 并交由 Handler 进行处理。
从 Looper 的文档上可以看到最通常的用法
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
比较简单的用法:
然后就可以通过 mHandler 来向该线程发送消息了,也就实现了线程间的消息传递。下面来简单走读一下源码。
public final class Looper {
// sThreadLocal.get() will return null unless you've called prepare().
static final ThreadLocal sThreadLocal = new ThreadLocal();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
public static void prepare() {
prepare(true);
}
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 static void prepareMainLooper() {
prepare(false);
synchronized (Looper.class) {
if (sMainLooper != null) {
throw new IllegalStateException("The main Looper has already been prepared.");
}
sMainLooper = myLooper();
}
}
/**
* Returns the application's main looper, which lives in the main thread of the application.
*/
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
/**
* 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();
}
...
Looper 主要方法就这几个,构造方法是私有的,提供了静态方法供我们创建实例。从 Looper.prepare 可以看到有初始化 Looper,并将其放入了 ThreadLocal,且保证一个线程只能持有一个 Looper。MessageQueue 是在 Looper 构造方法里创建的,所以是一对一绑定的。
prepareMainLooper 也是初始化 Looper 的,只是它比较特殊,创建的是 UI 线程的 Looper,并且不需要我们手动调用,这也就是为什么在 UI 线程不需要再初始化 Looper 了。通过 Android Studio 的 Find Usages [option + F7]功能可以轻松找到 ActivityThread.main()方法里初始化了 MainLooper。
Looper.prepareMainLooper();
...
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
Looper.loop();
Looper.loop() 的作用是是启动消息循环,分发 msg
/**
* 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;
}
msg.target.dispatchMessage(msg);
...
}
}
从代码上看也比较容易理解,从消息队列中获取消息,然后通过 msg.target.dispatchMessage(msg) 分发处理,留下的问题就是
一般情况下我们是通过 Handler handler = new Handler()
来创建 Handler,其调用了有参的构造方法
public Handler(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 that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
可以看到 Handler 默认关联当前线程的 Looper,当然也可以指定其他 Looper。
当通过 Handler.sendMessage 发送消息时,最后调用了 enqueueMessage
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
可以看到 msg.target = this,也就是当前的 Handler,而 Looper.loop 中分发消息的时候 msg.target.dispatchMessage(msg) 也就将消息交回了 Handler 进行处理。
Handler.dispatchMessage
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
private static void handleCallback(Message message) {
message.callback.run();
}
runOnUiThread(new Runnable() {
@Override
public void run() {
//
}
});
这是一种常用的给 UI 线程发消息的方式
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
public final boolean post(Runnable r){
return sendMessageDelayed(getPostMessage(r), 0);
}
private static Message getPostMessage(Runnable r) {
Message m = Message.obtain();
m.callback = r;
return m;
}
代码也非常好理解,在 UI 线程的话直接调用 run 方法,非 UI 线程则 postMessage,对应 Handler.dispatchMessage 的第一种处理方法,还是直接调用 run 方法。