相信很多同学都使用过Handler,他是安卓提供的跨线程通信方案,一般是在子线程发送消息,主线程处理消息更新ui。现在我们来分析一下Handler是怎么工作的。
-
本文涉及几个重要的对象:
Handler
负责发送消息,处理消息。
Lopper
负责循环从MessageQueue中取出消息,回调给Handler处理。
MessageQueue
是一个队列,先进先出,Handler发送的消息由他存储。
Message
消息对象。
ThreadLocal
Android源码中: static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(),用来存储Looper。
ThreadLocal是一个线程内部的存储类,可以用来存储数据,存储的数据只有这个线程可以访问。
-
Handler一般用法
主线程创建Handler
Handler mainHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
Log.e(TAG, msg.arg1 + "");
break;
default:
break;
}
}
};
子线程发送消息
new Thread(new Runnable() {
@Override
public void run() {
//可以做一些耗时操作,代码省略
//发送消息
Message msg = new Message();
msg.what = 1;
msg.arg1 = 999;
mainHandler.sendMessage(msg);
}
}).start();
查看Handler的构造方法
public Handler() {
this(null, false);
}
public Handler(Callback callback, boolean async) {
//省略一些代码
...
//获取Looper对象,绑定到Handler
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//获取MessageQueue对象,绑定到Handler
mQueue = mLooper.mQueue;
//Callback赋值
mCallback = callback;
mAsynchronous = async;
}
以上代码主要做了三件事情:
1.通过Looper.myLooper()方法获取Looper对象,我们看到如果Looper.myLooper()方法返回为空的话就会报错,所以在使用Handler之前必须要先初始化Looper。
2.获取MessageQueue对象。
3.Callback赋值。
-
分析Looper的初始化
我们接着看Looper类里的Looper.myLooper()方法,发现Looper类中有一个成员变量 static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(),Looper就是是存储在sThreadLocal里的。
public static @Nullable Looper myLooper() {
return sThreadLocal.get();
}
我们搜索整个Looper类,发现sThreadLocal只有一处存储操作,在一个私有方法prepare(boolean quitAllowed)方法中,再看Looper的构造方法,创建了一个MessageQueue。
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));
}
....
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
再搜索整个类发现有两处调用prepare(boolean quitAllowed),所以外部必须通过以下两个方法来初始化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();
}
}
public static void prepare() {
prepare(true);
}
但是平时工作中我们在主线程创建Handler并没有调用这两个方法,当我试着在主线程中主动调用prepareMainLooper()方法的时候发现app会崩溃,报错如下:
java.lang.RuntimeException: Only one Looper may be created per thread
at android.os.Looper.prepare(Looper.java:90)
at android.os.Looper.prepareMainLooper(Looper.java:117)
从报错中可以看出主线程已经初始化了Looper,不允许做二次初始化,所以我猜测主线程中的Looper初始化是Android系统源码中做的。我们都知道Activity的初始化是由ActivityThread完成的,所以猜测Looper的初始化是不是也在那呢?然后我们在AndroidSdk中搜索发现,有三个类调用了prepareMainLooper()方法:ActivityThread SystemServer Bridge;果然不出所料发现ActivityThread类。我们找到调用位置。
public static void main(String[] args) {
//省略一下代码
...
//初始化Looper
Looper.prepareMainLooper();
//省略一下代码
...
//开始循环从MessageQueue取消息
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
发现在ActivityThread类的main()方法中调用了prepareMainLooper()对创建了主线程的Looper,然后调用了Looper.loop()方法,我们接着看Looper.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 {
...
}
...
}
}
//MessageQueue 类里的next方法
Message next() {
//省略一些代码
...
int nextPollTimeoutMillis = 0;
for (;;) {
if (nextPollTimeoutMillis != 0) {
Binder.flushPendingCommands();
}
//native方法,如果nextPollTimeoutMillis为-1的时候就处于阻塞状态
nativePollOnce(ptr, nextPollTimeoutMillis);
synchronized (this) {
// Try to retrieve the next message. Return if found.
final long now = SystemClock.uptimeMillis();
Message prevMsg = null;
Message msg = mMessages;
//省略一些代码
...
if (msg != null) {
if (now < msg.when) {
// Next message is not ready. Set a timeout to wake up when it is ready.
nextPollTimeoutMillis = (int) Math.min(msg.when - now, Integer.MAX_VALUE);
} else {
//省略一些代码
...
return msg;
}
} else {
// msg为空nextPollTimeoutMillis置为-1,下次循环阻塞状态
nextPollTimeoutMillis = -1;
}
...
}
...
}
}
-
分析消息的分发
loop方法里有一个死循环,不断的从MessageQueue中取出消息,并调用msg.target.dispatchMessage(msg)方法。我们到Message类中发现msg.target是个Handler对象,紧接着我们去看Handler.dispatchMessage(msg)方法
public void dispatchMessage(Message msg) {
if (msg.callback != null) {
handleCallback(msg);
} else {
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
handleMessage(msg);
}
}
三种情况:
-
1.Message.callback(Message.callback是Runnable对象)不为空。
调用handleCallback(msg)方法。
方法中回调了Runnable对象的run()方法,我们知道直接调用run()方法并没有新开启线程,而是运行在当前线程中的,也就是说是在调用Looper.loop()方法的线程中。
private static void handleCallback(Message message) {
message.callback.run();
}
我们再接着找callback什么时候赋值的发现有两处可以由外部给callback赋值,但setCallback(Runnable r)方法是隐藏的外部无法调用所以我们只有使用obtain(Handler h, Runnable callback)方法可以给callback赋值。
public static Message obtain(Handler h, Runnable callback) {
Message m = obtain();
m.target = h;
m.callback = callback;
return m;
}
...
/** @hide */
public Message setCallback(Runnable r) {
callback = r;
return this;
}
所以Handler的用法还有这样一种:
private Handler handler = new Handler();
...
private void sendMsg(){
Message msg = Message.obtain(handler, new Runnable() {
@Override
public void run() {
Log.e(TAG, "Thread "+Thread.currentThread().getName());
}
});
msg.what = 0;
handler.sendMessage(msg);
}
....
//调用代码
new Thread(new Runnable() {
@Override
public void run() {
sendMsg();
}
}).start();
运行结果:Thread main
虽然我们是在子线程里发送的消息,但是Runnable中的run()方法中却是主线程:因为我们是在主线程创建的Handler,主线程的Handler在ActivityThread类的main方法中初始化了Looper,并调用了Looper.loop()方法,所以回调到callback的run()方法是在主线程,这样就实现了子线程与主线程通信。简单来说Looper.loop()运行在哪个线程,所以callback的run()方法就运行在哪个线程。
-
2.Message.callback为空且Handler.mCallback(Handler.mCallback是一个接口)不为空
调用mCallback.handleMessage(msg)方法。
我们查看Handler类发现,外部给mCallback的赋值可以通过调用以下几个方法:
public Handler(Callback callback) {
this(callback, false);
}
public Handler(Looper looper, Callback callback) {
this(looper, callback, false);
}
public static Handler createAsync(@NonNull Looper looper, @NonNull Callback callback) {
if (looper == null) throw new NullPointerException("looper must not be null");
if (callback == null) throw new NullPointerException("callback must not be null");
return new Handler(looper, callback, true);
}
所以Handler还有以下用法
private Handler handler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
Log.e(TAG, "Thread "+Thread.currentThread().getName());
return false;
}
});
private void sendMsg2(){
Message msg = Message.obtain();
handler.sendMessage(msg);
}
//调用代码
new Thread(new Runnable() {
@Override
public void run() {
sendMsg2();
}
}).start();
运行结果:Thread main
注意:我们发现mCallback.handleMessage(msg)有个boolean类型返回值,如果返回true,那么就不再调用Handler自己的handleMessage(msg)。
-
3.Message.callback为空且Handler.mCallback为空
调用Handler.handleMessage(msg)方法。
这种用法就是文中开头的最常见是的用法,回调我们再主线程创建的Handler重写的handleMessage(msg)方法。
至此Handler源码的主流程分析完毕