1

私はAndroid用のMonoでアプリを開発しています。

私はここ数日、メモリ不足の例外に苦しんでおり、希望を失い始めています!

200から600のアイテムを表示するListViewがあります。これらのアイテムは、ビットマップのサムネイルといくつかのテキストで構成されています。

AsyncTaskを使用してビットマップを非同期でデコードしています。コードは次のとおりです。

public class BitmapWorkerTask : AsyncTask
    {
        private WeakReference imageViewReference;
        public string thisURL = "";
        private int sampleSize = 0;
        private int reqHeight = 0;
        private int reqWidht = 0;

        public BitmapWorkerTask(ImageView imageView, int pSampleSize, int pReqWidth, int pReqHeight)
        {
            //_____________________________________________________________________
            // Use a WeakReference to ensure the ImageView can be garbage collected
            imageViewReference = new WeakReference(imageView);

            reqHeight = pReqHeight;
            reqWidht = pReqWidth;
            sampleSize = pSampleSize;
        }

        protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] @params)
        {
            string strUrl = @params[0].ToString();

            try
            {
                return DecodeSampleBitmapFromStream(strUrl, reqWidht, reqHeight);
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        protected override void OnPostExecute(Java.Lang.Object result)
        {
            base.OnPostExecute(result);

            if (IsCancelled)
            {
                result = null;
                Log.Debug("TT", "OnPostExecute - Task Cancelled");
            }
            else
            {
                Bitmap bmpResult = result as Bitmap;

                if (imageViewReference != null && bmpResult != null)
                {
                    ImageView view = imageViewReference.Target as ImageView;

                    if (view != null)
                    {
                        view.SetImageBitmap(bmpResult);
                    }
                }
            }
        }

        public static int CalculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight)
        {
            //_____________________________
            // Raw height and width of image
            int height = options.OutHeight;
            int width = options.OutWidth;
            int inSampleSize = 1;

            if (height > reqHeight || width > reqWidth)
            {
                if (width > height)
                {
                    inSampleSize = (int)Math.Round((float)height / (float)reqHeight);
                }
                else
                {
                    inSampleSize = (int)Math.Round((float)width / (float)reqWidth);
                }
            }

            return inSampleSize;

        }

        public static Bitmap DecodeSampleBitmapFromStream(string URL, int reqWidth, int reqHeight)
        {
            URL url = new URL(URL);

            try
            {
                //______________________________________________________________
                // First decode with inJustDecodeBounds=true to check dimensions
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.InJustDecodeBounds = true;
                BitmapFactory.DecodeStream(url.OpenConnection().InputStream, null, options);

                //______________________
                // Calculate inSampleSize
                options.InSampleSize = CalculateInSampleSize(options, reqWidth, reqHeight);

                //____________________________________
                // Decode bitmap with inSampleSize set
                options.InJustDecodeBounds = false;
                return BitmapFactory.DecodeStream(url.OpenConnection().InputStream, null, options);
            }
            catch (Exception ex)
            {
                return null;
            }
            finally
            {
                url.Dispose();
            }
        }

このメソッドを使用して、Lists GetView()関数からこのAsyncTaskを開始しています。

public void loadBitmap(string url, ImageView imageView)
        {
            if (Common.cancelPotentialWork(url, imageView))
            {
                BitmapWorkerTask task = new BitmapWorkerTask(imageView, 2, 80,80);

                AsyncDrawable asyncDrawable = new AsyncDrawable(null, null, task);

                imageView.SetImageDrawable(asyncDrawable);

                task.Execute(url);
            }
        }

一定期間はすべてが期待どおりに機能しますが、リストを上下にスクロールし続けると、最終的にOutOfMemoryExceptionsが表示され始め、アプリがクラッシュします。Androidリストがどのように機能するかについての私の理解は、ListItemビューが画面から移動するときにビューを破棄することですが、これは発生していないように感じます。

リストをスクロールするときにデコードしているすべてのビットマップは、何らかの理由でメモリに保持されているように感じますか?これらのビットマップが破棄されるのを妨げている、ここで何が欠けている可能性がありますか?Bitmap.Recycle()ビットマップがクリアされていることを確認するための呼び出しをどこに実装できますか?

GC.Collectを呼び出すたびに、メモリ使用量をかなり一定に保つように見えるテストを行いましたが、これは必要ないはずであり、スクロールのパフォーマンスに影響します。

を呼び出さずにリストをスクロールするGC.Collect()と、システムが実際に定期的な収集を行っていることを示すガベージコレクションメッセージが表示されないのはなぜですか?

どんな助けでもありがたいです、私はコーディングする意志を失っています!

4

1 に答える 1

1

Androidリストがどのように機能するかについての私の理解は、リストアイテムのビューが画面から移動するときにそれらを破棄することですが、これは発生していないように感じます。

これは正しくありません。

Androidが行うことは、一連のアイテムビューを保持し、画面から消えた後にそれらを再利用しようとすることです。これが、convertViewパラメーターの目的です。

質問に投稿されたアダプタコードが表示されないため、convertViewパラメータを使用するためのコードがわかりませんが、convertViewの場合は次のようになります。

  • 既存の非同期画像のフェッチ/変換をキャンセルする必要があります
  • 新しいものを開始する必要があります

MvvmCrossコードは、ここでの参照/例としては少し複雑すぎるかもしれませんが、少なくともMvxBindableListAdapter.csで使用されているconvertViewを見ることができます-を参照してくださいprotected virtual View GetBindableView(View convertView, object source, int templateId)

于 2012-11-13T12:12:23.267 に答える