【问题标题】:Android memory management for activity in onStop (or off screen)用于 onStop(或屏幕外)活动的 Android 内存管理
【发布时间】:2012-01-18 10:38:39
【问题描述】:

我想要达到的目标:

  • 减少不再出现在屏幕上的 Activity 的内存使用量,即另一个 Activity 已启动
  • 此活动仍位于导航堆栈内的能力,因此我假设我必须在 onStart 内重新构建在 onStop 中被破坏的内容,但不知道当所有视图/按钮都在时如何执行此操作使用 layout.xml 构建。

情况:

我有一个 Android 应用程序,它的图像非常重,但这些图像在许多布局上都是静态的,具有相同的背景、按钮图像、导航标题等。这使我能够非常轻松地构建布局而无需过多接触代码通过在 layout.xml 文件中指定所有 imageView、它们的 src 属性和位置。这很好用,很容易启动和运行,但是现在有很多报告说由于超出内存使用量而强制关闭。

为了清理并允许 gc 删除不在屏幕上的图像和视图,我在 onDestroy 方法中看到了一篇文章(见问题底部),它抓取了一个在布局中保留您的根元素并递归地遍历树删除视图并取消绑定它们。然而,这只是在按下后退按钮时触发并且根据文档不保证

因此,当我将新活动推入堆栈并且不想清理刚刚离开屏幕的内容时,onDestroy 对我没有帮助。但是使用 onDestroy 方法的好处是入口点从 onCreate 开始,所以视图都是正确构建的。当我在 onStop 中使用此方法时,当我开始一个新活动时,内存得到很好的清理,但是因为我已经对所有视图进行了核对,并且它们是使用 layout.xml 构建的,所以我不明白我需要如何或需要什么如果我破坏 onStop 中的所有内容,则重新构建 onStart,特别是考虑到我从未在代码中创建任何视图,因为它们都是由于 layout.xml 文件而设置的。

主要问题:当我开始一个新的 Activity 时如何清理内存?如果上下文处理正确,gc 是否会清除屏幕外的所有图像视图并自动重新构建它们?

这可以在 onStop 中以某种方式使用吗?

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

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

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

【问题讨论】:

    标签: android memory-management android-activity crash


    【解决方案1】:

    一) 使用 onCreate()/onDestroy() 将在 Activity 进入堆栈时进行分配,并在 Activity 从堆栈中弹出时取消分配。

    B) 使用 onStart()/onStop() 将在活动可见时分配,在活动不可见时取消分配。

    使用 A) 或 B)。不要混合它们,否则您会过于频繁地分配或取消分配。

    在您的情况下,我会将所有内容从 onCreate() 移动到 onStart(),并将所有内容从 onDestroy() 移动到 onStop()。

    另外,还可以考虑在 onStop() 中使用 this.setContentView(null) 或 this.setContentView(new View(this)),以确保旧视图可以被垃圾回收:

      @Override
      protected void onStop() {
        super.onStop();
        View root = findViewById(R.id.RootView);
        setContentView(new View(this)) 
        unbindDrawables(root);
        System.gc();
      }
    

    【讨论】:

      【解决方案2】:

      我认为任何活动回调都不是执行此操作的理想场所。你的活动一定会变得非常缓慢。

      我想如果可以的话,你宁愿保留图像,但如果系统需要资源,你想放弃。如果这(缓存)是您正在查看的内容,WeakReference 就是您的人。请参阅此excellent article,它将帮助您做出决定/理解。

      此外,我不认为 android 打算让我们开发人员担心从布局文件生成的视图何时被 gc'd。只要您没有强烈引用视图,就应该没问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-23
        • 1970-01-01
        • 2011-01-05
        • 2021-09-11
        • 1970-01-01
        • 2011-06-27
        相关资源
        最近更新 更多