Android - Кэш Bitmap занимает много памяти

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

Весь код фрагмента Bitmap Chapt довольно скопирован отсюда: http://developer.android.com/training/displaying-bitmaps/index.html

Я отлаживал код и проверял размер кучи в представлении DDMS в eclipse, и после этих строк кода происходит скачок в 15 мб:

        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);

в методе "decodeSampledBitmapFromResource".

Изображение 1024x800, 75kb jpg файл. Согласно тому, что я уже видел в Интернете, объем памяти, который предполагается использовать этому изображению, составляет около 1024 * 800 * 4 (байт на пиксель) = 3,125 мб

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

ИЗМЕНИТЬ

Я попытался использовать метод decodeFile, предложенный в ответе @ArshadParwez ниже. Используя этот метод, после метода BitmapFactory.decodeStream память увеличивается только на 3,5 Мб - проблема решена, но я хочу кэшировать растровые изображения непосредственно из ресурса.

Я заметил, что во время метода decodeResource есть 2 памяти "прыжки" - один из около 3,5 Мб, что разумно, и еще один странный один из 14mb. Для чего используются 14mb и почему это происходит?

Ответ 1

Изображения также масштабируются в соответствии с плотностью, поэтому они могут использовать много памяти.

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

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

(1024 * 2) * (800 * 2) * 4 = 13,107,200 байт.

Было бы еще хуже, если бы вы запустили его на устройстве xxhdpi (например, на HTC one и Galaxy S4).

Что вы можете сделать? Поместите файл изображения в нужную папку плотности (drawable-xhdpi или drawable-xxhdpi) или поместите его в drawable-nodpi (или в папку с ресурсами) и уменьшите изображение в соответствии с вашими потребностями.

Кстати, вам не нужно устанавливать options.inJustDecodeBounds = false, поскольку это поведение по умолчанию. Фактически вы можете установить значение null для параметров растрового изображения.

О масштабировании вниз вы можете использовать google way или мой способ каждый имеет свои преимущества и недостатки.

О кэшировании есть много способов сделать это. Наиболее распространенным является кеш LRU. Существует также альтернатива, которую я создал недавно (ссылка здесь или здесь), которая позволяет вам кэшировать много больше изображений и избежать наличия OOM, но это дает вам большую ответственность.

Ответ 2

Вы можете использовать этот метод для передачи изображения и получения растрового изображения:

public Bitmap decodeFile(File f) {
    Bitmap b = null;
    try {
        // Decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;

        FileInputStream fis = new FileInputStream(f);
        BitmapFactory.decodeStream(fis, null, o);
        fis.close();
        int IMAGE_MAX_SIZE = 1000;
        int scale = 1;
        if (o.outHeight > IMAGE_MAX_SIZE || o.outWidth > IMAGE_MAX_SIZE) {
            scale = (int) Math.pow(
                    2,
                    (int) Math.round(Math.log(IMAGE_MAX_SIZE
                            / (double) Math.max(o.outHeight, o.outWidth))
                            / Math.log(0.5)));
        }

        // Decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize = scale;
        fis = new FileInputStream(f);
        b = BitmapFactory.decodeStream(fis, null, o2);
        fis.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return b;
}

Ответ 3

@Ori Wasserman: по вашему запросу я использовал метод для получения изображений из папки ресурсов, и я тоже использовал изображение 7 МБ. Я помещал изображение 7 МБ в папку "res- > drawable" и со следующим кодом он не разбился и изображение было показано в изображении:

 Bitmap image = BitmapFactory.decodeResource(getResources(), R.drawable.image_7mb);
 loBitmap = Bitmap.createScaledBitmap(image, width_of_screen , height_of_screen, true);
 imageview.setImageBitmap(loBitmap);