我正在開發一款適用於Android的Mono應用程序。無法擊敗'內存不足'異常
我一直在努力解決過去幾天內存不足的問題,並開始失去希望!
我有一個ListView顯示200到600個項目的任何東西。這些項目由位圖縮略圖和一些文本組成。
我異步使用的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();
}
}
我開始使用這種方法的列表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);
}
}
一切按預期工作一段時間,但如果我不斷滾動瀏覽列表,我最終會開始獲取OutOfMemoryException
秒,並且應用程序崩潰。我對Android列表工作原理的理解是,它在屏幕上移動時會處理ListItem
視圖,但感覺好像沒有發生!
當我滾動列表時,感覺像所有這些位圖解碼都是出於什麼原因被存儲在內存中?我在這裏可能會丟失什麼,阻止了這些位圖被丟棄?我可以在哪裏實施致電Bitmap.Recycle()
以確保位圖清除?
我做了一個測試,我在每次調用GetView時都調用了GC.Collect,這似乎確保我的內存使用情況相當一致,但我知道這不應該被需要,它會影響滾動性能。
爲什麼當我通過我的列表滾動而沒有調用GC.Collect()
上午我沒有看到那些垃圾收集消息表明系統實際上正在做例行收集?
任何幫助表示讚賞,我失去了代碼的意志!
如果你能擊敗他們... ...購買更多的內存。 :) – gdoron