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