Android Handler消息机制(源码解析)
Handler 的设计初衷 是为了解决 多线程状态下控件状态混乱问题,通过Handler 让主线程在更新UI控件的状态,而Handler 是面试中常被问起的问题,然后本文就带大家走一遍Handler 消息发送机制。
Handler 的三个属性(熟记)
public class Handler{
final Looper mLooper;
final MessageQueue mQueue;
final Callback mCallback;
......
}
01
通过Handler 的源码我们可以看到,Handler里面封装了一个Looper, 消息队列MessageQueue 和一个CallBack ,这个CallBack 是什么?别忘了我们在Handler初始化的时候通过构造器传入了一个匿名内部类:
public interface Callback {
public Handler boolean handleMessage(Message msg);
}
嗯,先在清楚了,就是我们常用的handleMessage,我们接着往下说。Android 中一个线程只能有一个Looper,而消息队列是Looper的内部属性:
public final class Looper {
private static final String TAG = "Looper";
static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
private static Looper sMainLooper; // guarded by Looper.class
final MessageQueue mQueue;
final Thread mThread;
02
那么Handler 中的成员属性Looper 和消息队列是怎么被初始化赋值的呢?
public Handler(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;
mCallback = callback;
mAsynchronous = async;
}
看来这个问题也得到了解答,在Handler 构造器中已经完成了初始化,Handler 中的Looper 和消息队列 和 CallBack 都初始化了,Looper.myLooper() 会返回当前线程的Looper,那么问题来了,Handler 是如何把消息放入到消息队列的?在消息队列读出某个消息的时候又是怎样知道这个消息是来自哪个Handler实例?我们来看代码:
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
通过源码追踪到Handler 不管是调用 post() 还是 sendMessage还是sendEmptyMessage还是SendMessageDelay 最终都会调上面这段代码,将消息放入队列,我们还看到msg.target = this;这就是将Handler 实例与消息关联了,这样Looper 中队列中取出消息就知道是哪个Handler发送过来的消息了,这样我们上面的两个问题就清楚了。
03
知道是哪个Handler 发送过来的消息,那么就要处理消息了,都是通过回调完成,有两种回调途径,第一种就是 handler 初始化的时候 传入了CallBack ,那么回调的时候,就回调 handleMessage(Message message) 方法。第二种事handler 发送过来的消息是通过post(Runnable runnable) 这种方式发的消息,那么消息回调 就是 通过 runnable.run()了,我们可以再看Message的源码:
public final class Message implements Parcelable {
Runnable callback;
......
看清楚了没,你通过 handler.post(Runnable runnable)方法发的消息最终是回调这个Runnable 实例。
04
好了,到此为止我们的Handler 发送消息机制就讲完了,下面是在子线程中使用Handler 的方法:
Looper.prepare();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
Log.d(TAG," mHandler is coming");
handler_main.sendEmptyMessage(1);
}
};
mHandler.sendEmptyMessage(1);
Looper.loop();
loop()阻塞,后面的代码将不会执行。