研究員,我尋求你的幫助。在Xamarin.Android中使用位圖處理Android內存Android的內存
我有一個內存相關的問題。我真的不知道如何解決這個問題,所以我只會介紹我的代碼片段。請記住,雖然它在Xamarin.Android上,但它也適用於普通的Android。
我使用一個庫,它只是開始一個相機的意圖。我正在使用的庫(或組件)是:http://components.xamarin.com/view/xamarin.mobile。這不是真的有意義,但也許你可以指出我爲什麼我應該或不應該使用這個庫的其他見解。
無論如何,啓動相機並捕獲輸入。我使用以下代碼:
private void StartCamera() {
var picker = new MediaPicker (this);
if (! picker.IsCameraAvailable) {
Toast.MakeText (this, "No available camera found!", ToastLength.Short).Show();
} else {
var intent = picker.GetTakePhotoUI (new StoreCameraMediaOptions{
Name = "photo.jpg",
Directory = "photos"
});
StartActivityForResult (intent, 1);
}
}
onActivityForResult()方法在我從此相機意圖返回時調用。在該方法中,i執行以下操作:
protected override async void OnActivityResult (int requestCode, Result resultCode, Intent data)
{
// User canceled
if (resultCode == Result.Canceled)
return;
System.GC.Collect();
dialog = new ProgressDialog (this);
dialog.SetProgressStyle (ProgressDialogStyle.Spinner);
dialog.SetIconAttribute (Android.Resource.Attribute.DialogIcon);
dialog.SetTitle (Resources.GetString(Resource.String.dialog_picture_sending_title));
dialog.SetMessage (Resources.GetString(Resource.String.dialog_picture_sending_text));
dialog.SetCanceledOnTouchOutside (false);
dialog.SetCancelable (false);
dialog.Show();
MediaFile file = await data.GetMediaFileExtraAsync (this);
await ConvertingAndSendingTask (file);
dialog.Hide();
await SetupView();
}
然後,在我的ConvertingAndSendingTask()i中的圖象轉換成具有縮放的位圖的期望的尺寸。代碼如下:
public async Task ConvertingAndSendingTask(MediaFile file) {
try{
System.GC.Collect();
int targetW = 1600;
int targetH = 1200;
BitmapFactory.Options options = new BitmapFactory.Options();
options.InJustDecodeBounds = true;
Bitmap b = BitmapFactory.DecodeFile (file.Path, options);
int photoW = options.OutWidth;
int photoH = options.OutHeight;
int scaleFactor = Math.Min(photoW/targetW, photoH/targetH);
options.InJustDecodeBounds = false;
options.InSampleSize = scaleFactor;
options.InPurgeable = true;
Bitmap bitmap = BitmapFactory.DecodeFile(file.Path, options);
float resizeFactor = CalculateInSampleSize (options, 1600, 1200);
Bitmap bit = Bitmap.CreateScaledBitmap(bitmap, (int)(bitmap.Width/resizeFactor),(int)(bitmap.Height/resizeFactor), false);
bitmap.Recycle();
System.GC.Collect();
byte[] data = BitmapToBytes(bit);
bit.Recycle();
System.GC.Collect();
await app.api.SendPhoto (data, app.ChosenAlbum.foreign_id);
bitmap.Recycle();
System.GC.Collect();
} catch(Exception e) {
System.Diagnostics.Debug.WriteLine (e.StackTrace);
}
}
那麼,此方法將它發送好與多個存儲器更新的設備,但是,下端設備它在一個內存不足錯誤結束。或者反正幾乎是OOM。當Somethimes我進展順利,但是當我想要拍第二張或第三張照片時,它總是以OOM錯誤結束。
我意識到我正在做的是內存密集型。例如:
- 首先,我想要原始圖像的初始寬度和高度。
- 然後它被抽樣(我真的不知道它是否做得好)。
- 然後我加載採樣的位圖到內存中。
- 當我將它加載到內存中時,我的縮放位圖必須在回收()第一個位圖之前加載到內存中。
- 最終我需要一個字節[]通過網絡發送位圖。但是我需要在發佈我的縮放位圖之前先將其轉換。
- 然後我釋放我縮放的位圖併發送字節[]。
然後作爲最後一步,byte []需要從內存中釋放。我已經在我的BitmapToBytes()方法上做了如下所示的工作,但我想將其包含在其他的見解中。
static byte[] BitmapToBytes(Bitmap bitmap) { byte[] data = new byte[0]; using (MemoryStream stream = new MemoryStream()) { bitmap.Compress (Bitmap.CompressFormat.Jpeg, 90, stream); stream.Close(); data = stream.ToArray(); } return data; }
是否有人看到任何好的部分,我可以優化這個過程?我知道我的記憶力很大,但我想不出另一種方式。
應該提到的是,我總是希望我的圖像爲1600x1200(橫向)或1200x1600(縱向)。我通過以下方式計算該值:
public static float CalculateInSampleSize(BitmapFactory.Options options,
int reqWidth, int reqHeight) {
// Raw height and width of image
int height = options.OutHeight;
int width = options.OutWidth;
float inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
// Calculate ratios of height and width to requested height and
// width
float heightRatio = ((float) height/(float) reqHeight);
float widthRatio = ((float) width/(float) reqWidth);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
if(height < reqHeight || width < reqWidth) {
// Calculate ratios of height and width to requested height and
// width
float heightRatio = ((float) reqHeight/(float) height);
float widthRatio = ((float) reqWidth/(float) width);
// Choose the smallest ratio as inSampleSize value, this will
// guarantee
// a final image with both dimensions larger than or equal to the
// requested height and width.
inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
}
return inSampleSize;
}
有沒有人有任何建議或替代工作流?
我會這麼幫忙!
嘿傑克,你解決這個問題,我正要做類似的工作。 –