This Handler class should be static or leaks might occur

项目中使用到了Handler,按照如下方式编写:

handler = new Handler() {
                    @Override
                    public void handleMessage(@NonNull Message msg) {
                        super.handleMessage(msg);
                        switch (msg.what) {
                            case 参数:
                                //此处处理UI状态
                                break;
                            default:
                                break;
                        }
                    }
                };

Android Studio会发出警告:

This Handler class should be static or leaks might occur

  • 问题原因:在ADT 20 Changes我们可以找到这样一个变化:“New Lint Checks: Look for handler leaks: This check makes sure that a handler inner class does not hold an implicit reference to its outer class.” 就是说在ADT20以后加入了一条新的检查规则:确保类内部的handler不含有对外部类的隐式引用 。

1. 当Android应用启动的时候,会先创建一个应用主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。
2. 当在主线程中初始化Handler时,该Handler和Looper的消息队列关联。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。
3. 在Java中,非静态(匿名)内部类会引用外部类对象。而静态内部类不会引用外部类对象。
4. 如果外部类是Activity,则会引起Activity泄露 。

当Activity finish后,延时消息会继续存在主线程消息队列中1分钟,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。
要修改该问题,只需要按照Lint提示的那样,把Handler类定义为静态即可,然后通过WeakReference 来保持外部的Activity对象。


代码如下:
private static class MyHandler extends Handler{
        private final WeakReference mTarget;

        public MyHandler(Class class){
            mTarget= new WeakReference<>(class);
        }

        @Override
        public void handleMessage(@NonNull Message msg) {
            Class class=mTarget.get();
            if (class!=null){
                switch (msg.what) {
                    case 参数:
                        //此处处理UI状态
                        //因为该Handler为static,所以我们通过调用方法来获取外部类属性
                        class.属性;
                        class.方法;
                        break;
                    default:
                        break;
                }
            }
        }
    }
使用:
private MyHandler handler=new MyHandler(this);
handler.sendEmptyMessage(消息);

你可能感兴趣的:(This Handler class should be static or leaks might occur)