This Handler class should be static or leaks may occur (anonymous android.os.Handler)

问题引入 / 描述

用 Android Studio 开发时,如果在 Activity 中使用了非静态的匿名 Handler 类,lint 会提示 This Handler class should be static or leaks may occur (anonymous android.os.Handler)

匿名 Handler 类导致内存泄露的原因

在 AS 中错误提示处再次按 Ctrl+F1 即可看到详细描述和修改建议:

Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class; In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.

Java 中,非静态的内部类和匿名类都会隐式地持有一份对外部类的引用,而静态的内部类则不会包含对外部类的引用
也就是说,错误提示中的匿名 Handler 包含着对外部类(Activity 类)的引用。如果你给这个 Handler 发一个延迟执行的 Message,Message 会被添加进主线程 Looper 的 MessageQueue 中,且 Message 持有对 Handler 的引用。然而在延迟时间到达之前,Activity 可能已经被返回键等等 finish() 掉了。此时这个 Activity 对象已经没用啦,应该被 Garbage Collector 回收。然而 GC 扫描到这个 Activity 对象时,发现还有其他对象(我们可爱的 Handler)在引用它,因此不会回收这个 Activity,于是造成了内存泄露。
比如,在 3 分钟的延时之后发一个消息:mHandler.sendEmptyMessageDelayed(MSG_FOO, DELAY_FOO); 其中DELAY_FOO = 3 × 60 × 1000; 而 3 分钟内用户已经结束这个 Activity 去其他页面了,这个 Activity 就被泄露了。
一个 Activity 中有时还会持有更多其他类的引用,四大组件这些重量级的类千万小心不要发生泄露,否则内存浪费的太多。

解决方法

使用 WeakReference 在 Handler 与 Activity 之间搭建一座桥梁。若一个对象仅被 WeakReference 引用,则不能幸免于 GC。关于 Java 中的四种引用,可以参见 JDK 文档 Reachability 部分的说明

SHOW ME THE CODE

private final NotLeakHandler mHandler = new NotLeakHandler(this);

private static class NotLeakHandler extends Handler {
    private WeakReference<MainActivity> mWeakReference;

    public NotLeakHandler(MainActivity reference) {
        mWeakReference = new WeakReference<MainActivity>(reference);
    }

    @Override
    public void handleMessage(Message msg) {
        MainActivity reference = (MainActivity) mWeakReference.get();
        if (reference == null) { // the referenced object has been cleared
            return;
        }
        // do something
    }
}

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...
    mHandler.sendEmptyMessageDelayed(MSG_FOO, DELAY_FOO);
    // ...
}

AND…

REFERENCES

[1] http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html
[2] https://developer.android.com/reference/java/lang/ref/WeakReference.html
[3] https://docs.oracle.com/javase/8/docs/api/java/lang/ref/package-summary.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值