2

アクティビティでメモリが不足し続ける理由がわかりません。

アクティビティをロードすると、カスタム リストビュー アダプタにロードされる一連の画像があります。アクティビティを開始すると、画面が正常に読み込まれます。しかし、方向を変更したり、戻って再度開始したりすると、アクティビティでメモリ不足の例外が生成されます。

私の活動は次のようになります。

クラッシュする魚種の活動

私の活動のコードは次のとおりです。

    [Activity(Label = "FishinTales: Fish Species")]
public class Activity_View_FishSpecies : Activity
{
    #region Components
    private Model n_model;
    private ListView n_fishSpeciesListView;
    #endregion

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

        // Get Application Global Model
        this.n_model = ((MyApp) this.ApplicationContext).FishingData;

        // Set our view from the "View_FishSpecies" layout resource
        SetContentView(Resource.Layout.View_FishSpecies);

        this.n_fishSpeciesListView = FindViewById<ListView> (Resource.Id.xml_fishSpeciesListView);
        this.n_fishSpeciesListView.Adapter = new FishSpeciesListAdapter (this.ApplicationContext, this.n_model.SpecieManager.Species);
    }

    protected override void OnDestroy()
    {
        base.OnDestroy();
        this.unbindDrawables(FindViewById(Resource.Id.xml_root));
        this.n_fishSpeciesListView.Adapter = null;
        this.n_fishSpeciesListView = null;
    }

    private void unbindDrawables(View view) {
        if (view.Background != null) {
            view.Background.SetCallback(null);
        }
        if (view.GetType() == typeof(ViewGroup)) {
            for (int i = 0; i < ((ViewGroup) view).ChildCount; i++) {
                unbindDrawables(((ViewGroup) view).GetChildAt(i));
            }
            ((ViewGroup) view).RemoveAllViews();
        }
    }
}

public class FishSpeciesListAdapter : BaseAdapter
{
    Context n_context;
    List<AppCode.Specie> n_specieData;
    List<Bitmap> n_bitmapCache;

    public FishSpeciesListAdapter (Context context, List<AppCode.Specie> specieData)
    {
        this.n_context = context;
        this.n_specieData = specieData;
        this.n_bitmapCache = new List<Bitmap>();
        this.LoadBitmapsIntoCache();
    }

    private void LoadBitmapsIntoCache()
    {
        foreach(AppCode.Specie specie in this.n_specieData)
        {
            if (specie.RelatedMedia.AttachedPhotos.Count < 1)
            {
                this.n_bitmapCache.Add(BitmapFactory.DecodeResource(this.n_context.Resources, Resource.Drawable.Icon)); 
            }
            else
            {
                this.n_bitmapCache.Add(BitmapFactory.DecodeByteArray(specie.RelatedMedia.AttachedPhotos[0], 0, specie.RelatedMedia.AttachedPhotos[0].Length));  
            }
        }
    }

    public override int Count {
        get { return this.n_specieData.Count; }
    }

    public override Java.Lang.Object GetItem (int position)
    {
        return null;
    }

    public override long GetItemId (int position)
    {
        return 0;
    }

    // create a new ImageView for each item referenced by the Adapter
    public override View GetView (int position, View convertView, ViewGroup parent)
    {
        if(convertView==null){

            LayoutInflater li = LayoutInflater.FromContext(parent.Context);
            convertView = li.Inflate(Resource.Layout.Adapter_FishSpeciesIcon, null);
        }

        ImageView iconImage = (ImageView)convertView.FindViewById(Resource.Id.xml_adapter_fishSpeciesIconImage);
        TextView nameText = (TextView)convertView.FindViewById(Resource.Id.xml_adapter_fishSpeciesNameText);
        TextView scientificNameText = (TextView)convertView.FindViewById(Resource.Id.xml_adapter_fishSpeciesScientificNameText);

        nameText.Text = this.n_specieData[position].Name;
        scientificNameText.Text = this.n_specieData[position].ScientificName;
        iconImage.SetImageBitmap(this.n_bitmapCache[position]); 

        return convertView;
    }
}

OOM エラーが生成されるまでのすべてのプロセスのログを次に示します。

    Loading Defaults - Successfully Loaded Defaults
Grow heap (frag case) to 6.474MB for 314670-byte allocation
Clamp target GC heap from 32.512MB to 32.000MB
796824-byte external allocation too large for this process.
VM won't let us allocate 796824 bytes
Clamp target GC heap from 33.447MB to 32.000MB
--- decoder->decode returned false
UNHANDLED EXCEPTION: Java.Lang.OutOfMemoryError: Exception of type 'Java.Lang.OutOfMemoryError' was thrown.
at Android.Runtime.JNIEnv.CallStaticObjectMethod (intptr,intptr,Android.Runtime.JValue[]) <0x00080>
at Android.Graphics.BitmapFactory.DecodeByteArray (byte[],int,int) <0x001bb>
at FishinTales.FishSpeciesListAdapter.LoadBitmapsIntoCache () <0x00187>
at FishinTales.FishSpeciesListAdapter..ctor (Android.Content.Context,System.Collections.Generic.List`1<FishinTales.AppCode.Specie>) <0x000a3>
at FishinTales.Activity_View_FishSpecies.OnCreate (Android.OS.Bundle) <0x0012f>
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <0x00057>
at (wrapper dynamic-method) object.99ebf5db-74ad-4da9-b431-612691e1f213 (intptr,intptr,intptr) <0x00033>

  --- End of managed exception stack trace ---
java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=6855KB, Allocated=3089KB, Bitmap Size=26666KB)
    at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
    at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:625)
    at android.graphics.BitmapFactory.decodeByteArray(BitmapFactory.java:638)
    at fishintales.Activity_View_FishSpecies.n_onCreate(Native Method)
    at fishintales.Activity_View_FishSpecies.onCreate(Activity_View_FishSpecies.java:29)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1780)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1837)
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3242)
    at android.app.ActivityThread.access$1600(ActivityThread.java:132)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1037)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:143)
    at android.app.ActivityThread.main(ActivityThread.java:4196)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:507)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
    at dalvik.system.NativeStart.main(Native Method)

Unhandled Exception:
Java.Lang.OutOfMemoryError: Exception of type 'Java.Lang.OutOfMemoryError' was thrown.
at Android.Runtime.JNIEnv.CallStaticObjectMethod (intptr,intptr,Android.Runtime.JValue[]) <0x00080>
at Android.Graphics.BitmapFactory.DecodeByteArray (byte[],int,int) <0x001bb>
at FishinTales.FishSpeciesListAdapter.LoadBitmapsIntoCache () <0x00187>
at FishinTales.FishSpeciesListAdapter..ctor (Android.Content.Context,System.Collections.Generic.List`1<FishinTales.AppCode.Specie>) <0x000a3>
at FishinTales.Activity_View_FishSpecies.OnCreate (Android.OS.Bundle) <0x0012f>
at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (intptr,intptr,intptr) <0x00057>
at (wrapper dynamic-method) object.99ebf5db-74ad-4da9-b431-612691e1f213 (intptr,intptr,intptr) <0x00033>

  --- End of managed exception stack trace ---
java.lang.OutOfMemoryError: bitmap size exceeds VM budget(Heap Size=6855KB, Allocated=3089KB, Bitmap Size=26666KB)
    at android.graphics.BitmapFactory.nativeDecodeByteArray(Native Method)
    at android.gra

最初にアクティビティを表示すると、すべて問題ありません。アクティビティを離れて数回戻ってくると、最終的に上記のエラーでクラッシュします。これにより、ビットマップが適切にリサイクルされていないメモリリークが原因でエラーが発生していると推測されます。これらのビットマップを正確に解放する方法の例はありますか? ビットマップが Custom ListView Adapter クラス内にある場合、このトピックに関する情報を見つけるのは困難です。設定後に Bitmap.recycle を配置すると、ListView がリサイクルされたアイテムにアクセスしようとしているという別のエラーが表示されます。上記のコードに従って、どのように/いつリサイクルする必要がありますか。

4

1 に答える 1

1

使用している Android のバージョンを教えてください。Jelly Bean (Android 4.1.1) の場合は、このコード行を削除してください

this.n_bitmapCache.Add(BitmapFactory.DecodeResource(this.n_context.Resources, Resource.Drawable.Icon)); 

メモリリークが発生しているかどうかを確認します。

Android 4.1.1 へのアップデート後、私のアプリでもメモリ リークが発生し始めました。

setBackgroundResource(id);

に変えてみました

setBackground(context.getResources().getDrawable(id));

しかし、それでもメモリリークが発生していました。リソースからドローアブルまたはビットマップを作成しようとするとメモリ リークが発生するのは、私のコードのバグなのか、Jelly Bean のバグなのかを確認したいと思います。ご質問にお答えできず申し訳ありませんが、少なくともバグの原因を突き止め、Android チームに問題を提起することができます。

更新このリンク で解決策を見つけました

リソースの drawable フォルダから作成された Bitmaps には setBackgroundDrawable(null) を使用してください。

于 2013-01-10T06:19:31.510 に答える