outofmemoryerror injustdecodebounds cache bitmaps android design bitmap out-of-memory

android - injustdecodebounds - Capturando OutOfMemoryError en la decodificación Bitmap



injustdecodebounds android (4)

Aunque podría no ser una buena idea atrapar OutOfMemoryError con try-catch. Pero, a veces no tienes otra opción, porque todos nosotros odiamos los bloqueos de aplicaciones. Entonces, lo que puedes hacer es

  1. Captura OutOfMemoryError con try-catch
  2. Como, después de este error, su actividad puede volverse inestable, reiníciela.
  3. Puede deshabilitar las animaciones para que el usuario no sepa que la actividad se reinicia.
  4. Puede poner algunos datos adicionales con la intención de saber que la aplicación se bloqueó durante la ejecución anterior.

Cómo lo hice es:

try { //code that causes OutOfMemoryError } catch (Exception e) { // in case of exception handle it e.printStackTrace(); } catch (OutOfMemoryError oome) { //restart this activity Intent i=this.getIntent(); i.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); //disable animation //EXTRA_ABNORMAL_SHUTDOWN is user defined i.putExtra(this.EXTRA_ABNORMAL_SHUTDOWN, true); //put extra data into intent if you like finish(); //and finish the activity overridePendingTransition(0, 0); startActivity(i); //then start it(there is also restart method in newer API) return false; }

Y luego en onCreate of Activity puedes continuar (algo como esto):

boolean abnormalShutdown=getIntent().getBooleanExtra(this.EXTRA_ABNORMAL_SHUTDOWN, false); if (abnormalShutdown) { //Alert user for any error //get any extra data you put befor restarting. }

Este enfoque guardó mi aplicación. Espero que te ayude también!

¿Es una buena práctica capturar OutOfMemoryError incluso si ha intentado reducir el uso de memoria? ¿O deberíamos simplemente no captar la excepción? ¿Cuál es mejor práctica?

try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 4; bitmap = BitmapFactory.decodeFile(file, options); } catch (OutOfMemoryError e) { e.printStackTrace(); }

Gracias


Es una buena práctica atraparlo una vez y darle a decodeFile otra oportunidad. Atrápalo y llama a System.gc() e intenta decodificar de nuevo. Hay una alta probabilidad de que funcione después de llamar a System.gc() .

try { BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 4; bitmap = BitmapFactory.decodeFile(file, options); } catch (OutOfMemoryError e) { e.printStackTrace(); System.gc(); try { bitmap = BitmapFactory.decodeFile(file); } catch (OutOfMemoryError e2) { e2.printStackTrace(); // handle gracefully. } }


Hice algo así: capté el error solo para tratar de reducir la imagen hasta que funcione. Eventualmente no puede funcionar en absoluto; luego devuelve nulo; de lo contrario, con éxito, devuelve el mapa de bits.

Afuera decido qué hacer con el mapa de bits ya sea nulo o no.

// Let w and h the width and height of the ImageView where we will place the Bitmap. Then: // Get the dimensions of the original bitmap BitmapFactory.Options bmOptions= new BitmapFactory.Options(); bmOptions.inJustDecodeBounds= true; BitmapFactory.decodeFile(path, bmOptions); int photoW= bmOptions.outWidth; int photoH= bmOptions.outHeight; // Determine how much to scale down the image. int scaleFactor= (int) Math.max(1.0, Math.min((double) photoW / (double)w, (double)photoH / (double)h)); //1, 2, 3, 4, 5, 6, ... scaleFactor= (int) Math.pow(2.0, Math.floor(Math.log((double) scaleFactor) / Math.log(2.0))); //1, 2, 4, 8, ... // Decode the image file into a Bitmap sized to fill the View bmOptions.inJustDecodeBounds= false; bmOptions.inSampleSize= scaleFactor; bmOptions.inPurgeable= true; do { try { Log.d("tag", "scaleFactor: " + scaleFactor); scaleFactor*= 2; bitmap= BitmapFactory.decodeFile(path, bmOptions); } catch(OutOfMemoryError e) { bmOptions.inSampleSize= scaleFactor; Log.d("tag", "OutOfMemoryError: " + e.toString()); } } while(bitmap == null && scaleFactor <= 256); if(bitmap == null) return null;

Por ejemplo, con una imagen de 3264x2448, el ciclo itera 2 veces en mi teléfono y luego funciona.


Querrá ver si desea mostrar una imagen más pequeña / una imagen diferente / mostrar un mensaje de error personalizado al usuario. Su contenedor de acceso a la imagen puede detectar estos errores y devolver algunos códigos de error personalizados definidos en su código; su actividad que usa este código puede decidir qué hacer con el código de error - advertir al usuario, obligarlo a salir con un mensaje de error mejor que el que proporcionaría el sistema Android, etc.

Por cierto, no estás usando la variable de opciones en tu código de muestra.