众所周知的内存泄漏源AsyncTasks
持有对活动的引用,例如,在将任务声明为内部类时:
public class MyActivity extends Activity {
...
private class MyTask extends AsyncTask<Void, Void, Void> {
...
}
}
因为它们具有关联的后台线程(或线程池),所以只要线程正在运行,即使活动被解除,也会保留对活动的引用。
现在(如果我错了,请纠正我),当任务完成后,活动将再次可用于收集。
我的活动有:
我可以阻止内存泄漏只是取消定时器并在处理程序上调用removeCallbacks
吗?
示例:
public class MyActivity extends Activity {
Handler handler;
Timer timer;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
handler = new Handler();
timer = new Timer();
handler.postDelayed(new MyRunnable(), 10000);
timer.schedule(new MyTimerTask(), 1000);
}
@Override
protected void onDestroy() {
super.onDestroy();
handler.removeCallbacksAndMessages(null);
timer.cancel();
handler = timer = null;
}
private class MyTimerTask extends TimerTask {
...
}
private class MyRunnable implements Runnable {
...
}
}
我在我正在处理的项目中看到过这样的活动,我正在考虑重构它以使内部类静态并将WeakReferences添加到活动中。
问题在于内在类很方便,因为它们可以访问活动的私有变量和方法,并将它们更改为static也迫使我将活动类中成员的访问修饰符从private更改为package-default,从而使它们可用于任何其他类在同一个包中。这也打破了对称性,因为现在活动中的方法是包默认的,并且它们的对称对应方仍然是私有的(例如,我需要在活动中使stopFoo
方法可用于现在静态类,然后我应该用startFoo
做什么,而不是从那些类调用?)。那么需要访问的活动中的变量呢?我现在应该提供吸气剂吗?
对活动的弱引用的添加还在重构的静态类中引入了大量的空检查,因此它们仅在活动仍然存在时才起作用。除此之外,弱参考方法可能很难被公司中不熟练的程序员理解(此外,他们可能只是开始在任何地方使用它而不是真正需要的。)
简而言之,重构的活动看起来很丑,而前一个活动很整洁。所以我想知道基于内部类的设计是否可以接受,因为我知道如果活动结束后,如果一个runnable或计时器任务在短时间内运行,我真的不介意。
答案 0 :(得分:2)
现在(如果我错了,请纠正我),当任务完成后,活动将再次可用于收集
正确,假设没有别的东西有静态引用。
我可以阻止内存泄漏只是取消定时器并在处理程序上调用removeCallbacks吗?
这些步骤会有所帮助。而且,无论如何你都需要这样做 - 除非你停止它,否则你的Timer
会神奇地停止运行。
我真的不介意活动结束时运行或计时器任务是否在短时间内运行
从内存管理的角度来看,你的论点是合理的。虽然“避免非静态内部阶级”是一个很好的高级设计标准,但它并不是绝对的。
然而,恕我直言,你真正的问题不在于内存管理,而在于配置的变化。当用户旋转屏幕,更改语言,将其设备放入汽车底座等时,您的活动将被销毁并重新创建。然而,据推测,仍然需要来自任务的工作,但他们将与错误的活动实例交谈。使用保留的片段来管理这些任务有助于解决这个问题。