Handler内存泄漏原因
Handler是我们常用的一个对象,在之前的文章已经分析了Handler的工作机制,然而,在使用Handler的过程中容易造成内存泄漏。常见的场景如下。
场景一
public class MainActivity extends AppCompatActivity {
private CalendarPageView calendar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
}
},10000);
}
}
在Java中在内部创建对象之后会隐式的持有外部对象,也就是说new Handler()之后Handler对象对Activity就有了一个持有,那么此时finish掉Activity的话是没办法回收的。这就造成了内存泄漏。
场景二
private Handler handler = new Handler(){
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
Activity activity = MainActivity.this;
}
};
在里面Handler不仅仅是隐式的持有,也有显示的持有Activity,若执行延时操作也会导致Activity无法被回收。
对于隐式持有,Handler的postDelayed方法,实际上是先把Message添加到MessageQueue中,进而等待Message的执行,所以而Message又是在主线程的Looper中穿件,所以持有链接是ActivityThread->Looper->MessageQueue->Message->Handler->Activity
Handler内存泄漏解决方案
首先Handler的具体实现使用静态内部类的方式。再对外部的Activity进行弱引用。
static class MyHanler extends Handler{
WeakReference<Activity> activity;
public MyHanler(Activity activity) {
this.activity = new WeakReference<Activity>(activity);
}
@Override
public void dispatchMessage(Message msg) {
super.dispatchMessage(msg);
Activity act = activity.get();
if(null == act){
return;
}
}
}
然后再创建Handler,由于Activity是弱引用,这样当Activity结束之后Handler无法继续持有Activity,这样避免内存泄漏。
当然若是Handler有延时操作,那么Handler依然会存在,如果延时消息在Activity销毁之后没有存在的必要,那么我们可以在Activity销毁之后删除Handler的消息。
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
}