目录
前言
Android代码中涉及进程间通信的地方经常会使用Handler。
public class MainActivity extends AppCompatActivity {
//可能引入内存泄漏的方法
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
而上面这种用法可能会导致内存泄漏,比如使用如下代码,由于消息会在5分钟后发送,所以当用户进入并退出Activity后,在消息发送并处理完成之前,这个Activity是不会被回收的,这样就会导致内存泄漏。
public class MainActivity extends AppCompatActivity {
//可能引入内存泄漏的方法
private Handler handler=new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//5分钟后发送消息
handler.postDelayed(new Runnable() {
@Override
public void run() {
Log.e("测试","123");
}
},1000*10*5);
}
}
内存泄漏的原因
由于Handler、Looper和MessageQueue是一起工作的,在Android中一个应用启动后系统会默认创建一个用于处理主线程所有Message对象的Looper对象,它的生命周期贯穿于整个应用的生命周期,所以在主线程使用Handler的时候都会默认绑定这个Looper对象并关联MessageQueue,这时发送到MessageQueue的Message对象都会持有这个Handler对象的引用,这样Looper在处理消息的时候才能回调到Handler中年的handleMessage方法。因此如果Message对象还没有处理完成,那么Handler对象也就不会被垃圾回收。而在Java中非静态内部类会持有外部类的一个隐式引用,所以当Handler无法回收时由于Handler持有MainActivity的引用导致MainActivity也无法被回收,从而导致内存泄漏。
解决方法:将Handler改为静态内部类并使用弱引用
public class MainActivity extends AppCompatActivity {
private final InnerHandler mInnerHandler=new InnerHandler(this);
private final Runnable sRunnable=new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "解决方法", Toast.LENGTH_SHORT).show();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mInnerHandler.postDelayed(sRunnable,1000*60*5);
}
private static class InnerHandler extends Handler{
private final WeakReference<MainActivity> activityWeakReference;
public InnerHandler(MainActivity activity) {
this.activityWeakReference = new WeakReference<MainActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
MainActivity activity=activityWeakReference.get();
if(activity!=null){
}
}
}
}