Handler

基本要素

  • Message:消息的表示
  • MessageQueue:消息队列
  • Looper:消息循环,用于从消息队列中取出消息
  • Handler:消息处理

Handler的使用

  1. 初始化
    为了使用Handler,必须初始化。
  • 在主线程中,已经预先初始化了,所以可以直接使用Handler.
  • 而在自己创建的线程中,需要首先调用Looper.prepare();方法用来初始化MessageQueue和实例化Looper并设置Looper作为ThreadLocal的值,然后调用Looper.loop();方法进行消息的循环和处理。
  • 或者在构造时使用已经初始化的Looper,这样的话,消息的处理依然是在Looper初始化时所在的线程。
  1. 扩展Handler或者实现Handler.Callback接口作为Handler的构造参数,并实现handleMessage方法。实例化Handler子类时,应该在prepare和loop之间进行。

  2. 获得Handler对象实例,调用方法发送消息到消息队列。消息可以是Runnable或Message类型,分别是使用post和send方法。

HandlerThread的使用

HandlerThread thread = new HandlerThread("thread name" );
thread.start (); // 要把线程启动
 
Handler handler = new Handler(thread.getLooper ()) {
// 实现handleMessage方法
}

因为HandlerThread的run方法中,已经调用Looper的prepare和loop方法,这个线程已经在等待消息了。
Handler的构造函数中,使用了上面线程的Looper,因此,发送给Handler的消息会放到上面线程的Queue中,且在上面线程中执行。

post和sendMessage

post发送的Runnable最终被封装为Message,其中Runnable作为Message的callback域的值。
然后当Looper的消息循环收到消息时,根据Message的target域中的值,会调用对应Handler的dispatchMessage方法。
从方法中可以看到,如果Message的callback不为空(也就是使用post发送),那么直接调用Runnable的run方法,也就是说,在Looper所在的线程中同步处理。
否则,则在handleMessage方法中处理。默认的handleMessage方法为空。

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;
}
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();
}

Handler可能引起的内存泄漏和解决方案

首先,Looper的prepare方法会设置Looper到ThreadLocal中,而ThreadLocal变量作为Looper的static变量,又因为Message的target字段中包含Handler的引用,而Message被放入消息队列,所以导致Handler的生命周期比Activity长。

如果Handler在Activity作为内部类实现,那么就会保存一个Activity的引用。或者消息队列中包含尚未处理的Message,当Activity销毁后,导致Activity不能被垃圾回收。
解决办法:

  1. Handler作为静态类或外部类实现
  2. Activity作为参数传递给Handler的构造器
  3. Handler内部使用软引用或弱引用来保存Activity。
  4. 在handleMessage或run方法中使用Activity时,应该判断它是否为空。
  5. 另外,在Handler的post参数Runnable,也不应该使用内部类。

另外,当Activity销毁时,还在消息队列中排队的任务应该被取消掉,否则Activity还是不能被垃圾回收。可以通过调用Handler中的remove..方法或者mHandler.removeCallbacksAndMessages(null); 删除所有的Runnable和Message。

参考

Android消息处理机制(Handler、Looper、MessageQueue与Message)
Android App 内存泄露之Handler

你可能感兴趣的:(Handler)