Handler是安卓中常见的实现异步操作的方法,使用简单,但是操作不注意很容易造成内存泄漏。
在使用Handler的时候,我们常将Handler定义为内部类,也可以单独一个类定义一个Handler,单独定义是不会持有activity引用的,所以不会造成内存泄漏,而在使用内部类的时候,会持有activity的引用,当activity finish掉的使用,Handler仍然持有该activity的引用,这就造成了内存泄漏的原因。
讲讲如何解决Handler定义为内部类所造成内存泄漏的解决方案。
根据官方提示,需要将内部类申明为static 静态内部类,再使用弱引用获取外部类对象。
因为内部类默认持有外部类的引用,就默认持有activity的引用,而静态内部类则不会;而之所以要使用弱引用,只是因为我们需要用到外部类的变量和方法,所以需要一个外部类对象,而使用弱引用的话就不会持有外部类引用。
下面看例子,正常会造成内存泄漏的写法如下:
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handleroom);
findViewById(R.id.btn_send).setOnClickListener(this);
tv = findViewById(R.id.tv);
// 延时5min发送一个消息,此时handler是持有activity引用的
mHandler.sendEmptyMessageDelayed(1, 5 * 60 * 1000);
}
测试结果可以通过横竖屏切换,然后观察AS控制台内存占用数据即可知晓。
下面是使用static跟弱引用的写法:
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_handleroom);
findViewById(R.id.btn_send).setOnClickListener(this);
tv = findViewById(R.id.tv);
MyHandler handler = new MyHandler(this);
handler.sendEmptyMessageDelayed(0, 5 * 60 * 1000);
}
private static class MyHandler extends Handler {
private WeakReference<HandlerOOMActivity> weakReference;
private HandlerOOMActivity activity;
public MyHandler(HandlerOOMActivity activity) {
weakReference = new WeakReference<>(activity);
this.activity = activity;
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e(TAG, "handleMessage: ");
HandlerOOMActivity activity = weakReference.get();
switch (msg.what) {
case 0:
break;
}
}
}
同样可以观察AS控制台内存占用数据,与未申明为static做对比即可知道。
还有一种请况,Handler在消息处理完后,是会被系统随时回收的,那么即使我们在用内部类的时候,在持有外部类引用的情况下,只要在外部类销毁的时候,让Handler把所有的消息都处理完,即调用Handler的removeCallbacksAndMessages,也是可以避免内存泄漏的。但是一般还是建议采用静态内部类+弱引用的方法。
如何避免Handler引起的内存泄漏,总结三点信息如下:
1、使用static 修饰内部类handler,但是一般会弱引用activity对象,因为要使用activity对象中的成员
2、使用单独定义handler,同样可以弱引用activity
3、可以使用内部类的handler,但是在activity销毁的时候在onDestroy方法中调用Handler的removeCallbacksAndMessages方法