Handler

作者: 我欲举头望明月 | 来源:发表于2015-11-25 04:23 被阅读0次

    基本要素

    • 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

          本文链接:https://www.haomeiwen.com/subject/imxrhttx.html