java.lang.OutOfMemoryError при преобразовании более 100 строк в массивы байтов

Во-первых, я понимаю, что вопросы, касающиеся java.lang.OutOfMemoryError и растровых изображений, уже задавались много раз. Я также проверил страницу Эффективное отображение растровых изображений.

Мой вариант использования:

Я храню два растровых изображения разного размера в виде строк в базе данных SQLite. Первый размер растровых изображений составляет 50 % ширины экрана, а второй размер — 100 % ширины экрана.

Я использую RecyclerView, который отображает изображения в ImageViews, которые составляют либо 50%, либо 100% ширины экрана, поэтому загружаемые растровые изображения не больше, чем они должны быть, и они имеют соответствующий размер перед изображениями. получено из базы данных.

Я также загружаю растровые изображения с помощью AsyncTask.

У меня есть более 180 различных элементов в RecyclerView, поэтому у меня создается более 360 растровых изображений (т.е. число изображений * theDifferentSizesOfEachImage). Я покрываю строковые версии изображений в массивы байтов с помощью этого кода: byte [] byteArray = Base64.decode(encodedString, Base64.DEFAULT);

Проблема

Активность смогла загрузить более 170 различных изображений без получения java.lang.OutOfMemoryError, если только я не перезапустил ту же активность (например, загрузил активность, затем воссоздал активность, снова щелкнув ее в навигационном ящике, а затем повторив этот процесс) и повлек за собой java.lang.OutOfMemoryError при преобразовании строк в массивы байтов.

Я преобразовываю массив байтов в растровое изображение с помощью библиотеки Glide, используя следующий код:

 Bitmap bitmap = Glide.with(context).load(byteArray).asBitmap()
 .dontTransform().dontAnimate().skipMemoryCache(true)
 .diskCacheStrategy(DiskCacheStrategy.NONE).into(-1, -1).get();

Кратко о моем вопросе

Как избежать появления java.lang.OutOfMemoryError при преобразовании строк в массивы байтов?

Примечание

После создания растрового изображения с помощью Glide я вызываю recycle() для данного растрового изображения, а затем устанавливаю для него значение null.

Я также уже использую android:largeHeap="true" в своем манифесте Android.

заранее спасибо

Изменить

Вот как я создаю Bitmap Strings:

 ByteArrayOutputStream baos = new  ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.WEBP,100, baos);
        byte [] b =baos.toByteArray();
     String bitmapString = Base64.encodeToString(b, Base64.DEFAULT);

person Micah Simmons    schedule 25.06.2016    source источник
comment
почему бы вам не сжать его перед сохранением ...   -  person ΦXocę 웃 Пepeúpa ツ    schedule 25.06.2016
comment
Спасибо за ваш ответ. Если вы имеете в виду сжатие растровых изображений, я уже делаю это, я отредактировал свой вопрос, и вы можете увидеть, как я сжимаю растровые изображения перед преобразованием их в строки.   -  person Micah Simmons    schedule 25.06.2016
comment
Я храню два растровых изображения разного размера в виде строк в базе данных SQLite - почему? Храните их в виде файлов с именами файлов в базе данных. Или сохраните их как столбцы BLOB, чтобы, по крайней мере, исключить преобразование String.   -  person CommonsWare    schedule 25.06.2016
comment
Спасибо за ответ. Я храню два разных размера растровых изображений, потому что я использую изображения обоих разных размеров. Сохранение их в виде файлов и сохранение имен файлов в базе данных или сохранение изображений в столбцах BLOB поможет избежать ошибки java.lang.OutOfMemoryError. Если оба варианта помогут избежать java.lang.OutOfMemoryError, какой вариант будет наиболее эффективным с точки зрения использования памяти?   -  person Micah Simmons    schedule 25.06.2016


Ответы (1)


Что бы я предложил вам отказаться от вашего подхода, это просто не сработает с большим набором изображений, и вы уже много работаете над своим потоком для обработки. Никогда не следует хранить такое изображение в файле sqllite. Вы должны просто преобразовать свое растровое изображение в файл с уникальным именем или может быть таким же (зависит от вашего варианта использования), тогда вы можете просто сохранить этот файл в каталоге приложения и сохранить путь к файлу в базе данных. Вот код, который вам поможет.

File pictureFile = getOutputMediaFile(getActivity(), MEDIA_TYPE_IMAGE);
        if (pictureFile == null) {
            return;
        }
        Bitmap bitmap =BitmapFactory.decodeByteArray(data,0,data.length);

            FileOutputStream fos = new FileOutputStream(pictureFile);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
            fos.flush();
            fos.close();

частный файл getOutputMediaFile (контекст контекста, int m) {

    File mediaStorageDir = context.getFilesDir();

    if (!mediaStorageDir.exists()) {
        if (!mediaStorageDir.mkdirs()) {
            Log.d("Fade", "failed to create directory");
            return null;
        }
    }
    // Create a media file name
    String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss")
            .format(new Date());

    File mediaFile=new File(mediaStorageDir.getPath()+File.separator
                + "IMG_" + timeStamp + ".JPG");

    return mediaFile;
}

Теперь у вас есть файл, и теперь вы можете просто сохранить путь к файлу в базе данных, и когда это необходимо, вы всегда можете получить свой файл из хранилища с помощью glide. Это также сделает вашу базу данных быстрой для запросов.

Таким образом, вам не понадобятся какие-либо изменения в gradle или где-либо еще. Попробуй это.

person Ankush Sharma    schedule 25.06.2016
comment
Спасибо за ваш ответ. Я либо попытаюсь сохранить изображения в виде файлов в виде массивов байтов, если это решит проблему java.lang.OutOfMemoryError. Считаете ли вы, что сохранение изображений в виде файлов, а затем преобразование файлов в изображения более эффективно с точки зрения использования памяти, чем сохранение изображений в виде массивов байтов в столбце BLOB в базе данных SQLIite с последующим преобразованием этих массивов байтов в растровые изображения? - person Micah Simmons; 25.06.2016
comment
Да, сэр, также вы не конвертируете ни один файл в изображение. Изображение, сохраненное в хранилище, само по себе является файлом. Теперь вы собираетесь просто указать библиотеке glide прямой путь к вашему файлу и оставить кэширование и отображение изображения в вашем представлении glide, что делает это очень эффективно. Просто попробуйте и всегда практикуйте это решение. То, что вы делали раньше, это просто пустая трата памяти. Сохраняя изображения в виде файла внутри папки приложений, вы не откроете галерею, поэтому она будет работать именно так, как вы этого хотите. - person Ankush Sharma; 25.06.2016
comment
Спасибо за информацию. Я попытаюсь сохранить изображения в виде файлов, и если это решит java.lang.OutOfMemoryError, я приму ваш ответ. - person Micah Simmons; 25.06.2016