Ловкость OutOfMemoryError в декодировании Растровое изображение

Является ли хорошей практикой поймать OutOfMemoryError, даже если вы попытались каким-то образом сократить использование памяти? Или мы просто не поймаем исключения? Какой из них лучше?

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

благодаря

Solutions Collecting From Web of "Ловкость OutOfMemoryError в декодировании Растровое изображение"

Его хорошая практика, чтобы поймать его один раз и дать decodeFile еще один шанс. Поймайте его и вызовите System.gc() и повторите попытку декодирования. Существует высокая вероятность того, что он будет работать после вызова 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. } } 

Я сделал что-то вроде этого: я поймаю ошибку только для того, чтобы попытаться уменьшить изображение до тех пор, пока оно не сработает. В конце концов, он не может работать вообще; Затем возвращает null; В противном случае, с успехом, возвращает растровое изображение.

Снаружи я решаю, что делать с растровым изображением, является ли оно нулевым или нет.

 // 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; 

Например, с изображением 3264×2448, цикл повторяется 2 раза на моем телефоне, а затем он работает.

Вы хотите поймать его, если хотите отобразить меньшее изображение / другое изображение / показать пользователю пользовательское сообщение об ошибке. Ваша оболочка для доступа к изображениям может улавливать эти ошибки и возвращать определенные коды ошибок, определенные в вашем коде; Ваша деятельность, использующая этот код, может решить, что делать с кодом ошибки – предупредить пользователя, заставить его выйти с лучшим сообщением об ошибке, чем тот, который предоставит система Android и т. Д.

Кстати, вы не используете переменную options в своем примере кода.

Хотя может быть неплохо поймать OutOfMemoryError, используя try-catch. Но иногда у вас нет выбора, потому что все мы ненавидим атаки приложений. Итак, что вы можете сделать, это

  1. Поймать OutOfMemoryError с помощью try-catch
  2. Поскольку после этой ошибки ваша активность может стать нестабильной, перезапустите ее.
  3. Вы можете отключить анимацию, чтобы пользователь не знал, что активность перезапущена.
  4. Вы можете поместить некоторые дополнительные данные в намерение знать, что приложение было разбито во время предыдущего запуска.

Как я это сделал:

  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; } 

И затем в onCreate of Activity вы можете возобновить (что-то вроде этого):

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

Этот подход сохранил мое приложение. Надеюсь, это тоже поможет!