2013-06-21 39 views
5

Natknąłem się na wiele pytań w stackoverflow dotyczących tego błędu, ale nie znalazłem wyjaśnienia odpowiedniego rozwiązania dla mojego scenariusza.Błąd systemu Android: java.lang.OutOfMemoryError: rozmiar bitmapy przekracza budżet VM

W mojej aplikacji Android muszę pozwolić użytkownikowi kliknąć przycisk, aby otworzyć Galerię i wybrać obraz. A następnie musi załadować ten konkretny wybrany obraz do ImageView w moim układzie (UI).

Wykonanie tego jest całkiem w porządku. Poniżej znajduje się kod, którego używam, aby to osiągnąć.

się Udostępnij kliknięcia przycisku ->

 Intent intent = new Intent(); 
     intent.setType("image/*"); 
     intent.setAction(Intent.ACTION_GET_CONTENT); 
     startActivityForResult(Intent.createChooser(intent,"Select Picture"), REQUEST_UPLOAD_IMG); 

A potem onActivityResult ->

@Override 
protected void onActivityResult(int requestCode, int resultCode, Intent data) 
{  
    //super.onActivityResult(requestCode, resultCode, data);   
    if(resultCode == Activity.RESULT_OK) 
    { 
     if(requestCode==REQUEST_UPLOAD_IMG) 
     {    
      Uri selectedImageURI = data.getData(); 
      uploadImgVW.setImageURI(selectedImageURI);    
     } 
     else 
     { 
      Toast.makeText(MainActivity.this, "You can only select an Image.", Toast.LENGTH_LONG).show(); 
     } 
    } 
} 

Ale jeśli użytkownik wybrać obraz o wyższej wielkości (jak 2MB od rozmiaru), aplikacja zakończ z następującym błędem. Ale na normalnych obrazach (na poziomie KB) jest całkiem dobrze i zastanawiam się, co mogę zrobić dla tego problemu (aby poradzić sobie z tą sytuacją błędu). Dzięki ...

Error ->

06-20 16:43:58.445: E/AndroidRuntime(2075): FATAL EXCEPTION: main 
06-20 16:43:58.445: E/AndroidRuntime(2075): java.lang.OutOfMemoryError: bitmap size exceeds VM budget 
+0

Powtórz tę czynność z powodzeniem po każdym załadowaniu bitmapy if (b itmap! = null) { bitmap.recycle(); –

+0

Aplikacja ulega awarii nawet po raz pierwszy. To jest problem. Dodałem również następujące kody, aby uruchomić moduł do zbierania śmieci w kliknięciu przycisku. [System.gc(); Runtime.getRuntime(). Gc(); ] – JibW

+1

@JibW garbage collection nie jest problemem, musisz dostosować rozmiar obrazu jak gunnar mówi – tyczj

Odpowiedz

7

Istnieje szereg artykułów, które opisują how to manage the bitmaps sprawnie. Patrząc na swój kod, wczytujesz obraz, nie wiedząc, jak duże jest to, i ostatecznie staniesz w obliczu tych problemów, szczególnie jeśli załadujesz i przetworzysz wiele obrazów.

Pomysł opisany w polega na załadowaniu już zmniejszonej mapy bitowej (najpierw sprawdzisz, jak duży jest obraz do załadowania, następnie obliczysz współczynnik zmniejszania i dopiero potem załadujesz skalowany obraz w dół). W tym celu musisz najpierw poznać wymiary ImageView, będziesz musiał użyć BitmapFactory.decode(...), ponieważ masz Uri pliku docelowego do wyświetlenia. Uri do pliku powinno być trywialne.

Musisz również sprawdzić zużycie pamięci w swojej aplikacji ... możesz mieć inne zasoby, które zwisają w pamięci i musisz je wyczyścić. Używam bardzo pomocnego narzędzia - MAT. Bardzo dobry artykuł na ten temat może be found here. Autor, Patrick Dubroy, przeprowadził bardzo interesującą sesję w Google IO 2011 na ten temat. Check that out, dla mnie to było bardzo pomocne ...

1

zmienić rozmiar obrazu, a następnie ustawić

public static Bitmap decodeUri(Context c, Uri uri, final int requiredSize) 
      throws FileNotFoundException { 
     BitmapFactory.Options o = new BitmapFactory.Options(); 
     o.inJustDecodeBounds = true; 
     BitmapFactory.decodeStream(c.getContentResolver().openInputStream(uri), null, o); 

     int width_tmp = o.outWidth 
       , height_tmp = o.outHeight; 
     int scale = 1; 

     while(true) { 
      if(width_tmp/2 < requiredSize || height_tmp/2 < requiredSize) 
       break; 
      width_tmp /= 2; 
      height_tmp /= 2; 
      scale *= 2; 
     } 

     BitmapFactory.Options o2 = new BitmapFactory.Options(); 
     o2.inSampleSize = scale; 
     return BitmapFactory.decodeStream(c.getContentResolver().openInputStream(uri), null, o2); 
    } 

lub użyć jak ten

if(resultCode == RESULT_OK){ 
       Uri selectedImage = data.getData(); 
       InputStream imageStream = null; 
       try { 
        imageStream = getContentResolver().openInputStream(selectedImage); 
       } catch (FileNotFoundException e) { 
        // TODO Auto-generated catch block 
        e.printStackTrace(); 
       } 
       Bitmap yourSelectedImage = BitmapFactory.decodeStream(imageStream); 
       profileImage.setImageBitmap(Bitmap.createScaledBitmap(yourSelectedImage , 120, 120, false)); 
       } 
0

można spróbować to ...

BitmapFactory.Options options = new BitmapFactory.Options(); 
options.inTempStorage = new byte[16*1024]; 

Bitmap bitmapImage = BitmapFactory.decodeFile(path, options); 
+0

Witaj, Ryderz, ten sam błąd również występuje. – JibW