동료 개발자, 도움을 요청합니다.Xamarin.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() 메서드가 호출됩니다. 이 방법에서, 난 다음을 수행
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. 때로는 잘 지내지 만 두 번째 또는 세 번째 사진을 찍고 싶을 때는 항상 OOM 오류로 끝납니다.나는 내가하는 일이 메모리 집약적이라는 것을 알고있다. 예 :
- 처음에는 원본 이미지의 너비와 높이를 원합니다.
- 그런 다음 샘플링됩니다 (실제로 잘 수행되는지는 알 수 없습니다).
- 그런 다음 샘플 된 비트 맵을 메모리에로드합니다.
- 메모리에로드 할 때 첫 번째 비트 맵 Recycle() 전에 크기 조정 된 비트 맵을 메모리에로드해야합니다.
- 궁극적으로 웹을 통해 비트 맵을 보내기 위해 바이트 []가 필요합니다. 하지만 먼저 스케일 된 비트 맵을 릴리스하기 전에 먼저 변환해야합니다.
- 그런 다음 스케일 된 비트 맵을 해제하고 [] 바이트를 보냅니다.
마지막 단계에서 바이트 []도 메모리에서 해제해야합니다. 이미 아래 그림과 같이 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;
}
누군가 권장 사항이나 대체 워크 플로우를 갖고 있습니까?
나는 이것으로 많은 도움이 될 것입니다!
잭이 봐, 당신은 해결 되었습니까 따라 대신 주 스레드에서 실행 파일을 디코딩하는 비동기 방식을 사용하는 것이 좋습니다 : [참고 이것은 단지 전체 이미지 무승부 후 작동] 이 문제는 지금 막 비슷한 것을하려고하고 있습니다. –