2

在具有 24MB 堆的 WVGA800 屏幕的 API_14 模拟器中运行我的视图的背景图像有问题,看起来在视图导航之间没有释放可绘制对象,并且在显示 3 个视图后,出现内存不足异常使视图膨胀.

该应用程序以 SplashScreenActivity 开始,它具有 480x800 PNG 作为其背景图像,用于启动启动画面。应用程序继续导航到下一个视图,该视图也显示一个新的 480x800 像素。第三个屏幕导航还包含 480x800 PNG,当内存不足错误发生时。首先,我尝试在 axml 布局中设置背景。然后我尝试了从 SplashScreenActivity.OnCreate() 和其他两个视图 OnCreate() 方法中的代码设置背景的替代方法。我在其他地方读到了从单声道虚拟机处理可绘制版本以防万一这是问题。另一个有帮助的技巧是在 OnCreate() 开始时强制进行 GC,这会留下 12% 的堆空闲,但效果有限。

public class SplashScreenActivity: MvxBaseSplashScreenActivity
{
    public SplashScreenActivity() : base(Resource.Layout.SplashScreen) { }

    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        using (var drawable = Resources.GetDrawable(Resource.Drawable.LoadingScreen))
            Window.SetBackgroundDrawable(drawable);
    }
}

而第二种观点

public class GameView : MvxBindingActivityView<GameViewModel>
{
    public GameView() { SoundBinding.GameView = this; }

    protected override void OnViewModelSet() { SetContentView(Resource.Layout.GameView); }

    protected override void OnCreate(Bundle bundle) 
    {
        GC.Collect();
        base.OnCreate(bundle);
        using (var drawable = Resources.GetDrawable(Resource.Drawable.GameScreenBackground))
            Window.SetBackgroundDrawable(drawable);
    }
}

毕竟,在使用背景填充第三个类似视图时,应用程序仍然会耗尽内存。有时它会起作用,然后随着屏幕循环最终发生。我查看了 MAT 上的堆转储,可以看到两个 3.5M 大小的 bitmapDrawables。我假设这是我的两个位图。对于第二个 BitmapDrawable,我可以清楚地看到持有它的视图。内存中还有另一个位图,但我看不到它到 GC 根的路径是什么。这必须是第一个 SplashScreenActivity 视图中第一个加载的 PNG。这是没有弱引用的 GC 根的 MAT 路径。也有一个弱裁判持有它。

android.graphics.Bitmap @ 0x4134fb08 |           40 |     3,456,056
|- mBitmap android.graphics.drawable.BitmapDrawable @ 0x4134f568 |           64 |           136
|  |- mBackgroundDrawable com.android.internal.policy.impl.PhoneWindow @ 0x41356cc8 Native Stack  |          200 |         1,168
|  |- mBGDrawable com.android.internal.policy.impl.PhoneWindow$DecorView @ 0x41357560 Native Stack|          560 |           968
|  '- Total: 2 entries                                                                                 |              |              
|- mBitmap android.graphics.drawable.BitmapDrawable$BitmapState @ 0x4134f460                      |           40 |            40
 |  '- referent java.lang.ref.WeakReference @ 0x4134ff40 |           24 |            24
'- Total: 2 entries  |              |              

所以提问时间。如何确保在下一个视图膨胀之前释放这些可绘制对象?是否有必要在代码中设置背景而不是视图的布局?我是否需要通过将回调设置为 null 来取消绑定Drawables(),如此处所示Drawable vs Single reusable Bitmap with memory 更好?? 我调查了视图的 OnDestroy() 覆盖,但我发现在创建新视图之前没有调用这些视图。当从一个视图导航到另一个视图时,可以确保视图被销毁,这有助于在下一个视图膨胀之前释放我的资源。

任何关于如何在我的应用程序中更好地管理这些资源的建议都将不胜感激。

4

1 回答 1

1

是否有一个简单的示例应用程序可以发布到可以重现此行为的任何地方?你能在非 Mvvm 应用程序中重现同样的问题吗?在非 MonoDroid Java 应用程序中?

感觉就像您可能在 Android 或 MonoDroid 层看到了泄漏。我相信会议应用程序中的所有视图都在使用Window.SetBackgroundDrawable,并且我没有在那里报告问题。(可能我的图像更小?)

作为一种解决方法,您可以尝试的一件事是覆盖Activity 生命周期中的 OnPause 和 OnResume 方法,以清除和重置背景可绘制对象。

但是,这只是一种解决方法......我认为在这里完成一个完整的解决方案是值得的。

于 2012-11-10T08:25:28.830 回答