Android消息机制Handler
当我们调用handler.sendMessage()发送一个Message时,实际上是将这个Message发送到MessageQueue中,然后与当前线程绑定的Looper会不断地从MessageQueue中取出新的Message,调用msg.target.dispatchMessage(msg)将消息分发到handlerMessage()中。
1.实例化Handler
//Handler
public Handler(Callback callback, boolean async) {
//...
//检查当前的线程是否有Looper,不存在就抛异常(主线程已为我们创建好了Looper)
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread " + Thread.currentThread()
+ " that has not called Looper.prepare()");
}
//Looper持有一个MessageQueueu
mQueue = mLooper.mQueue;
//...
}
一个完整的Handler使用例子应该这样创建:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
//问题1:handler.handleMessage(msg)是在什么时候回调的呢?
public void handleMessage(Message msg) {
// 处理接收到的消息
}
};
Looper.loop();
}
}
2.Looper.prepare()
Looper提供了Looper.prepare()来创建Looper,借助ThreadLocal来实现与当前线程的绑定
//Looper
private static void prepare(boolean quitAllowed) {
//Android规定一个线程只能够拥有一个与自己关联的Looper
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//在当前线程绑定一个Looper
sThreadLocal.set(new Looper(quitAllowed));
}
在Looper中,维持着一个Thread对象和MessageQueue对象
private Looper(boolean quitAllowed) {
//创建一个新的MessageQueue quitAllowed参数表示这个Queue是否能够被退出
mQueue = new MessageQueue(quitAllowed);
//将线程对象指向了创建Looper的线程
mThread = Thread.currentThread();
}
3.Looper.loop()
Looper.loop()会不断地从MessageQueue(MessageQueue.next())中获取Message,并调用msg.target.dispatchMessage(msg)回到Handler来分发消息。
Looper.loop()是个死循环,死循环并不是导致主线程卡顿的真正原因,真正原因是循环后面的事件没有得到分发。looper()方法最终会调用msg.target.dispatchMessage(msg)将事件分发出去,所以不会造成卡顿或者ANR。
//Looper
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 (;;) {
//不断地从MessageQueue获取消息
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
// ...
try {
//问题2:Looper.loop()死循环中的msg.target是什么时候被赋值的呢?
msg.target.dispatchMessage(msg);
dispatchEnd = needEndTime ? SystemClock.uptimeMillis() : 0;
} finally {
//...
}
//...
//回收message
msg.recycleUnchecked();
}
}
msg.target.dispatchMessage(msg)中的msg.target就是发送该消息的Handler,这样就回调到了Handler那边去了
//Handler
public void dispatchMessage(Message msg) {
//msg.callback是Runable
if (msg.callback != null) {
handleCallback(msg);
} else {
//可以利用 Callback 这个拦截机制来拦截 Handler 的消息。
if (mCallback != null) {
if (mCallback.handleMessage(msg)) {
return;
}
}
//问题1:回调到Handler的handlerMessage方法
handleMessage(msg);
}
}
4.handler.sendMessage()
无论是handler.sendMessage(msg)还是handler.sendEmptyMessage(what),最终都追溯到以下方法
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
//引用Handler中的MessageQueue
//这个MessageQueue就是创建Looper时被创建的MessageQueue
MessageQueue queue = mQueue;
if (queue == null) {
RuntimeException e = new RuntimeException(
this + " sendMessageAtTime() called with no mQueue");
Log.w("Looper", e.getMessage(), e);
return false;
}
//将新来的Message加入到MessageQueue中
return enqueueMessage(queue, msg, uptimeMillis);
}
private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {
//问题2:msg.target被赋值的时机:在handler.sendMessage(msg)后,执行enqueueMessage的时候
msg.target = this;
if (mAsynchronous) {
msg.setAsynchronous(true);
}
return queue.enqueueMessage(msg, uptimeMillis);
}
5.关于Handler引起的内存泄漏
handler.png可以看到IDE标黄了代码,并给出了提示。
假如我们用Handler发送延时消息,延时期间用户关闭了Activity,Message依旧会由Handler进行处理,即Message会持有Handler,而又因为Java的特性,非静态内部类会持有外部类的强引用,使得Activity会被Handler持有,这样导致了Activity无法被GC识别回收,这样最终导致了Activity泄漏。
解决该问题得有效方案:将Handler定义为静态内部类,在内部类中持有Activity的弱引用,并是移除所有消息。(被弱引用关联的对象只能存活到下一次垃圾回收之前,被销毁的Activity会被回收内存)
private static class SafeHandler extends Handler {
private WeakReference<HandlerActivity> mActivity;
public SafeHandler(HandlerActivity activity) {
this.mActivity = new WeakReference(activity);
}
@Override
public void handleMessage(final Message msg) {
HandlerActivity activity = mActivity.get();
if (activity != null) {
activity.handleMessage(msg);
}
}
}
并在Activity.onDestory()前移除消息,加一层保障
@Override
protected void onDestroy() {
safeHandler.removeCallbacksAndMessages(null);
super.onDestroy();
}
注:以上系统源码基于 Android 28