正确的onDestroy()/如何避免内存泄漏

时间:2013-02-07 19:41:04

标签: android view memory-leaks android-activity

我阅读了一些关于如何避免Android内存泄漏的文章,但我仍然不确定我是否做对了。

  1. 我的应用程序包含一个Activity
  2. 我在该活动中没有任何私人或静态成员,所有代码都是从onCreate()内启动的。
  3. 有一些自包含的静态类,其静态实例有时会引用ContextView s。在我的onDestroy()方法中,我将所有这些实例设置为null。
  4. 我回收了所有Bitmap s。
  5. Q1 :这够了吗?

    令我困惑的是你可以在网上找到的禁忌的经典例子(http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/):

    @Override
    protected void onCreate(Bundle state) {
      super.onCreate(state);
    
      TextView label = new TextView(this);
      label.setText("Leaks are bad");
    
      setContentView(label);
    }
    

    我认为,只要onCreate完成,label就会超出范围并且已经过GCed。

    Q2 :这怎么会造成内存泄漏?

    我的活动基本上是这样的:

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    
        /* Statics */
        AssetUtils.initIndex(this);
        BitmapLoader.startInstance(this);
    
        /* frame */
        ViewGroup frame = (ViewGroup) getLayoutInflater().inflate(R.layout.frame, null);
        this.setContentView(frame);
    
        /* create controller */
        Controller controller = new Controller(frame, getLayoutInflater());
    
        /* START */
        controller.start();
    }
    
    @Override
    public void onDestroy() {
        super.onStop();
    
        /* Statics */
        AssetUtils.destroyInstance();
        BitmapLoader.destroyInstance();
    }
    

    内部Controller我偶尔使用Context检索View#getContext(),将其传递给手动创建的View等。它永远不会静态地存储在某个地方,只会存在于所有返回Controller的类的成员变量中。

    Q3 :有什么我忽略的吗?

1 个答案:

答案 0 :(得分:22)

Q1。你已经脱离了背景(没有开玩笑的意思:)。

如果您看到原始文章,泄漏实际上发生在引入位图字段的下一代码片段中。 Roman然后清楚地解释了为什么泄漏。您显示的代码不会泄漏。

http://www.curious-creature.org/2008/12/18/avoid-memory-leaks-on-android/

Q2。仅在没有其他选择的情况下使用Activity上下文,并且绝不允许在范围大于其引用的Activity范围的内容中引用它。你所展示的代码并没有泄漏,因为没有任何上下文引用的范围大于你的Activity。你怀疑它确实存在吗?

Q3。当使用Bitmaps,静态引用或不使用静态引用时,我习惯在onPause()中从视图中取消绑定Bitamps(请记住onDestroy()不能保证,但它有点无关紧要,好像你被摧毁一样,你的进程被杀了所以GC不是一个问题)。链接的文章还解释了如何执行此操作。我已将其作为处理位图的任何活动的模板模式。

[编辑]

抱歉,我刚刚检查过。这篇文章没有说明如何解开。这是我使用的模式:

@Override
protected void onPause()
{
        super.onPause();

        unbindDrawables(findViewById(R.id.mainLayout));
        System.gc();
}


@Override
protected void onDestroy()
{
        super.onDestroy();

        unbindDrawables(findViewById(R.id.mainLayout));
        System.gc();
}

private void unbindDrawables(View view)
{
        if (view.getBackground() != null)
        {
                view.getBackground().setCallback(null);
        }
        if (view instanceof ViewGroup && !(view instanceof AdapterView))
        {
                for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++)
                {
                        unbindDrawables(((ViewGroup) view).getChildAt(i));
                }
                ((ViewGroup) view).removeAllViews();
        }
}

mainLayout是活动布局的根视图。

我包括onDestroy()因为我可以手动完成()我的Activity。

请注意。调用system.gc()是一个复杂的主题,可能想要省略它。这里有一些很好的讨论为什么它可能不是一件好事,主要关注性能。但是,在我看来,当一项活动被破坏时,暗示现在是执行GC的好时机不会造成伤害。在破坏活动的开销中,将不必要地调用它的效率低下。