Как избавиться от ООМ при работе с Bitmap?

308
26 ноября 2016, 19:16

Я работаю с Bitmap и рабочий процесс выглядит так

Юзер делает фото, оно сохраняется в файл после чего открывается юзеру для подтверждения. Если юзер подтверждает фото то выполняется crop части фото и еще раз показывается юзеру для подтверждения.

Таким образом юзер делает 5 фото.

Так вот после первой фото и все хорошо. Фото показывается юзеру и проходит 2 этапа подтверждения.

Но на втором фото юзеру показывается фото , он ее подтверждает и получает ошибку

FATAL EXCEPTION: AsyncTask #2
    Process: com.fittingroom.newtimezone, PID: 7196
            java.lang.RuntimeException: An error occurred while executing doInBackground()
                at android.os.AsyncTask$3.done(AsyncTask.java:309)
                at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
                at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
                at java.util.concurrent.FutureTask.run(FutureTask.java:242)
                at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
                at java.lang.Thread.run(Thread.java:818)
            Caused by: java.lang.OutOfMemoryError: Failed to allocate a 63489036 byte allocation with 16777216 free bytes and 60MB until OOM
                at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
                at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)
                at android.graphics.BitmapFactory.decodeStreamInternal(BitmapFactory.java:882)
                at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:858)
                at android.graphics.BitmapFactory.decodeFile(BitmapFactory.java:478)
                at com.fittingroom.newtimezone.presenters.PresenterActivityAcceptNotAccept.getCroppedBitmapFromPath(PresenterActivityAcceptNotAccept.java:65)
                at com.fittingroom.newtimezone.presenters.PresenterActivityAcceptNotAccept.access$200(PresenterActivityAcceptNotAccept.java:16)
                at com.fittingroom.newtimezone.presenters.PresenterActivityAcceptNotAccept$1.doInBackground(PresenterActivityAcceptNotAccept.java:41)
                at com.fittingroom.newtimezone.presenters.PresenterActivityAcceptNotAccept$1.doInBackground(PresenterActivityAcceptNotAccept.java:31)
                at android.os.AsyncTask$2.call(AsyncTask.java:295)
                at java.util.concurrent.FutureTask.run(FutureTask.java:237)
                at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234) 
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113) 
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588) 
                at java.lang.Thread.run(Thread.java:818)

вот код в котором появляется ошибка

private Bitmap getCroppedBitmapFromPath(String path) {
    final File photo = new File(path);
    final BitmapFactory.Options options = new BitmapFactory.Options();
    final Bitmap bitmap = BitmapFactory.decodeFile(photo.getAbsolutePath(), options);
    int height = bitmap.getHeight();
    Bitmap result;
    final Matrix matrix = new Matrix();
    matrix.postRotate(90);
    final double centerX = height * 0.5;
    final double centerY = height / 447 * 480;
    final double widthAndHeight = height / 447 * 160;
    final int pointY = (int) (centerX - widthAndHeight / 2);
    final int pointX = (int) (bitmap.getWidth() - centerY - widthAndHeight / 2);
    final int widthAndHeightResult = (int) widthAndHeight;
    result = Bitmap.createBitmap(bitmap, pointX, pointY, widthAndHeightResult, widthAndHeightResult, matrix, false);
    return result;
}

Вот в этой строчке

final Bitmap bitmap = BitmapFactory.decodeFile(photo.getAbsolutePath(), options);

может как то нужно освобождать байты с которыми Bitmap работает?

или может как то уменьшить размер картинки?

Answer 1

Можно, если это например jpeg или png работать с картинкой меньшего качества, а потом уже приводить ее к нормально виду, когда закончили работу.

А как менять качество:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 8;
final Bitmap bitmap = BitmapFactory.decodeFile(selectedImageUri.getPath(), options);

Да и в плюс данного метода:

  • наверняка эта картинка маленькая, результирующая нет смысла показывать хорошее качество
READ ALSO
транслировать в Java 8 stream

транслировать в Java 8 stream

Есть вот такой метод

371
Деплой приложения с maven

Деплой приложения с maven

На сколько я понял от сюда, деплой приложения на сервере происходит через добавление новых jar файлов с новым функционалом к уже существующим

245
Сравнение двух файлов построчно

Сравнение двух файлов построчно

Есть два txt-файлаВ первом лежит список нужных строк, во втором большое скопление рандомного бреда из которого нужно взять строки, начинающиеся...

292