2013-11-14 2 views
0

동료 개발자, 도움을 요청합니다.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 오류로 끝납니다.

나는 내가하는 일이 메모리 집약적이라는 것을 알고있다. 예 :

  1. 처음에는 원본 이미지의 너비와 높이를 원합니다.
  2. 그런 다음 샘플링됩니다 (실제로 잘 수행되는지는 알 수 없습니다).
  3. 그런 다음 샘플 된 비트 맵을 메모리에로드합니다.
  4. 메모리에로드 할 때 첫 번째 비트 맵 Recycle() 전에 크기 조정 된 비트 맵을 메모리에로드해야합니다.
  5. 궁극적으로 웹을 통해 비트 맵을 보내기 위해 바이트 []가 필요합니다. 하지만 먼저 스케일 된 비트 맵을 릴리스하기 전에 먼저 변환해야합니다.
  6. 그런 다음 스케일 된 비트 맵을 해제하고 [] 바이트를 보냅니다.
  7. 마지막 단계에서 바이트 []도 메모리에서 해제해야합니다. 이미 아래 그림과 같이 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; 
    } 

누군가 권장 사항이나 대체 워크 플로우를 갖고 있습니까?

나는 이것으로 많은 도움이 될 것입니다!

+0

잭이 봐, 당신은 해결 되었습니까 따라 대신 주 스레드에서 실행 파일을 디코딩하는 비동기 방식을 사용하는 것이 좋습니다 : [참고 이것은 단지 전체 이미지 무승부 후 작동] 이 문제는 지금 막 비슷한 것을하려고하고 있습니다. –

답변

2

이것은 매우 지연된 답글 일지 모르지만 같은 문제가있는 사람에게 도움이 될 수 있습니다.

  • 계산 된 InSampleSize 값 (옵션)을 사용하여 파일을 비트 맵으로 디코딩합니다. 이 자체는 CreateScaledBitmap 대신 축소 된 비트 맵을 생성합니다.
  • 출력으로 고해상도 이미지를 기대하는 경우 OutOfMemory 문제를 처리하기가 어려우면 입니다. 해상도가 더 높은 이미지는 눈에 띄는 이점을 제공하지 않지만 보람있는 메모리 인 을 여전히 차지하며보기에 의해 수행 된 추가 배율 때문에 추가 성능 오버 헤드가 발생합니다. [xamarin doc]
  • 이미지 뷰의 높이 및 너비와 관련된 비트 맵 대상 너비 및 높이를 계산합니다. MeasuredHeight와 MeasuredWidth Property로 이것을 계산할 수 있습니다.
  • 는 [DecodeFileAsync] 더 자세히 들어

이이 http://appliedcodelog.blogspot.in/2015/07/avoiding-imagebitmap.html

관련 문제