活动内的内部课程是不可接受的吗?

时间:2014-01-10 17:12:43

标签: java android memory-leaks android-asynctask inner-classes

众所周知的内存泄漏源AsyncTasks持有对活动的引用,例如,在将任务声明为内部类时:

    public class MyActivity extends Activity {

        ...

        private class MyTask extends AsyncTask<Void, Void, Void> {
            ...
        }
    }

因为它们具有关联的后台线程(或线程池),所以只要线程正在运行,即使活动被解除,也会保留对活动的引用。

现在(如果我错了,请纠正我),当任务完成后,活动将再次可用于收集。

我的活动有:

  • Runnables定义为内部类,并通过处理程序发布在主线程上。
  • TimerTasks被定义为内部类。

我可以阻止内存泄漏只是取消定时器并在处理程序上调用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或计时器任务在短时间内运行,我真的不介意。

1 个答案:

答案 0 :(得分:2)

  

现在(如果我错了,请纠正我),当任务完成后,活动将再次可用于收集

正确,假设没有别的东西有静态引用。

  

我可以阻止内存泄漏只是取消定时器并在处理程序上调用removeCallbacks吗?

这些步骤会有所帮助。而且,无论如何你都需要这样做 - 除非你停止它,否则你的Timer会神奇地停止运行。

  

我真的不介意活动结束时运行或计时器任务是否在短时间内运行

从内存管理的角度来看,你的论点是合理的。虽然“避免非静态内部阶级”是一个很好的高级设计标准,但它并不是绝对的。

然而,恕我直言,你真正的问题不在于内存管理,而在于配置的变化。当用户旋转屏幕,更改语言,将其设备放入汽车底座等时,您的活动将被销毁并重新创建。然而,据推测,仍然需要来自任务的工作,但他们将与错误的活动实例交谈。使用保留的片段来管理这些任务有助于解决这个问题。