为什么Handler会造成内存泄漏?
AS的风险提示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.
(由于Hander被声明为一个内部类,它可能阻止外部类被GC回收。如果Handler是在非主线程使用Looper或MessageQueue,那么不会有问题。如果Handler是在主线程中使用Looper或MessageQueue,那么你将需要修复Handler的声明,如下:声明Handler为静态类;在定义Handler时,定义一个外部类的弱引用给Handler;使得通过弱引用来持有外部类的成员。)
首先,Java中的匿名内部类和非静态内部类都会隐式持有当前类的引用。
所以,如上定义匿名内部类Handler,Handler便会持有外部类(多为Activity或Fragment),如果Handler发出的消息尚在其队列MessageQueue中等待被处理,此时外部类即使被finish调,也不能被GC回收,因此造成内存泄漏。
怎么避免Handler的内存泄漏?
方法1. 使用静态内部类(推荐)
静态内部类不会持有外部类的引用,所以不会引起外部类的泄漏。
如下:
public class TestActivity extends AppCompatActivity {
private TextView mContentText;
private Handler mHandler = new MyHandler(this);
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
mContentText = findViewById(R.id.main_test1);
//延迟发送消息
mHandler.sendEmptyMessageDelayed(1, 10 * 60 * 1000);
}
private static class MyHandler extends Handler {
private final WeakReference<TestActivity> mTargetWeak;
public MyHandler(TestActivity activity) {
mTargetWeak = new WeakReference<>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (mTargetWeak.get() != null) {
if (msg.what == 999) {
mTargetWeak.get().mContentText.setText("msg");
}
}
}
}
}
方法2. 在外部类销毁时,清空Handler队列
如下:
@Override
protected void onDestroy() {
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
小结
一般来讲,java中长生命周期的对象强持有短生命周期的对象,都有内存泄漏的风险。
代码千万行,防漏第一条。防漏不做好,日后泪千行~
网友评论