2

24MB ヒープの WVGA800 画面を使用して API_14 エミュレーターで実行すると、ビューの背景画像に問題が発生します。ビュー ナビゲーション間でドローアブルが解放されていないように見え、3 つのビューが表示された後、ビューを膨張させるメモリ不足の例外が発生します。 .

アプリは、起動時のスプラッシュ スクリーンに使用する背景画像として 480x800 PNG を持つ SplashScreenActivity で開始します。アプリは、新しい 480x800 ピクセルも表示する次のビューに移動します。3 番目の画面のナビゲーションにも 480x800 の PNG が含まれており、これはメモリ不足エラーが発生したときのものです。まず、axmlレイアウトで背景を設定してこれを試しました。次に、SplashScreenActivity.OnCreate() メソッドと他の 2 つのビュー OnCreate() メソッドのコードから背景を設定する別の方法を試しました。これが問題である場合に備えて、ドローアブルを処分するとモノVMから解放されることを他の場所で読みました。助けになったもう 1 つのトリックは、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);
    }
}

そして2つ目の見方

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);
    }
}

このすべての後、アプリケーションは、3 番目の同様のビューをバックグラウンドで膨張させると、まだメモリ不足になります。時々それはうまくいきますが、画面が循環するにつれて最終的に発生します。MAT のヒープ ダンプを見ると、サイズが 3.5M の bitmapDrawable が 2 つあることがわかります。これらは私の2つのビットマップだと思います。2 番目の 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 に設定して unbindDrawables() を unbindDrawables() にする必要がありますか? ? ビューの OnDestroy() オーバーライドを調査しましたが、新しいビューが作成される前にこれらが呼び出されていないことがわかりました。あるビューから別のビューに移動するときに、ビューが破棄されることを確認するために離れているため、次のビューが膨張する前にリソースを解放するのに役立ちます。

アプリでこれらのリソースをより適切に管理する方法についてアドバイスをいただければ幸いです。

4

1 に答える 1

1

この動作を再現できる、どこにでも投稿できる簡単なサンプル アプリはありますか? 非 Mvvm アプリで同じ問題を再現できますか? MonoDroid 以外の Java アプリでは?

Android または MonoDroid レイヤーでリークが発生している可能性があります。会議アプリのすべてのビューが使用されWindow.SetBackgroundDrawableていると思いますが、そこで問題が報告されたことはありません。(もしかして私の画像が小さい?)

回避策として、 Activity Lifecycle内の OnPause および OnResume メソッドをオーバーライドして、バックグラウンドのドローアブルをクリアおよびリセットすることを試みることができます。

ただし、これは回避策にすぎません...完全な解決策に取り組むことは、ここで価値があると思います。

于 2012-11-10T08:25:28.830 に答える