Кэширование растровых изображений - проверка текущего бюджета виртуальной машины - PullRequest
1 голос
/ 08 марта 2012

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

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

private Bitmap bitmap = null;
public Bitmap getBitmap(int id) {
    if(bitmap == null) bitmap = expensiveNetworkOperationToGetBitmap(id);
    return bitmap;
}

(пожалуйста, игнорируйте проблемы блокировки потоков)

ОднакоВполне возможно, что пользователь будет просматривать многие элементы.Каждый из них медленно занимал часть памяти, в конечном итоге перебирал бюджет и ломал приложение.

Что заставляет меня задать вопрос: Можно ли динамически определять, когда ваше кэширование достигает предела? Если это так, то можно начинать уничтожать старые изображения по мере добавления новыхиз них.Ниже приведен пример кода:

private HashMap<Integer, Bitmap> bitmaps = new HashMap<Integer, Bitmap>();
public Bitmap getBitmap(int id) {
    Bitmap bitmap;
    if(!bitmaps.contains(id)) {
        if(// Bitmap budget close to being exeeded?) {
            bitmaps.keyValues().get(0).recycle();
            bitmaps.remove(bitmaps.keyValues().get(0));
        }
        bitmap = expensiveNetworkOperationToGetBitmap(id);
        bitmaps.put(id, bitmap);
    else {
        bitmap = bitmaps.get(id);
    }
    return bitmap;
}

Еще раз, пожалуйста, не обращайте внимания на неэффективность выталкивания первого растрового изображения из HashMap.

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

Ответы [ 2 ]

1 голос
/ 08 марта 2012

Вы можете использовать что-то вроде коллекции SoftReference для растровых изображений, если вы хотите, чтобы ваш кэш рос практически неограниченно до пределов кучи VM.

http://developer.android.com/reference/java/lang/ref/SoftReference.html

Возможно, вы также захотите внедрить в свою деятельность onLowMemory (), чтобы также хорошо играть с системой, если вы хотите иметь такой большой кэш.

1 голос
/ 08 марта 2012

Вы не можете обнаружить, тогда вы достигаете предела кучи (вы не можете получить размер занятой кучи во время выполнения AFAIK)

Вот что я делаю.

У меня естьlistView и определить, сколько изображений было отображено в любое время (видимые строки | столбцы).Когда добавляется новое растровое изображение, я проверяю в адаптере, какие кэшированные изображения не отображаются при просмотре изображений.Если я найду один или несколько я .recycle () их.Когда мне нужно перезагрузить изображение (которое я сохранил в кеше памяти телефона), я не только проверяю, существует ли это изображение в кеше, я также проверяю, используется ли растровое изображение повторно.Если переработано, я перекодирую его, иначе, если нет, я загружаю его снова.Это самая безопасная операция.Я также уменьшаю масштаб изображения в зависимости от того, где показано.Например, если у меня есть изображение 200x200, а imageView - только 20x20, я уменьшу изображение в 10 раз.

Таким образом, Android будет обрабатывать каждое отдельное изображение, отображаемое на нем.Это все о переработке растровых изображений, при этом способ сохранения андроида перерабатывает сами изображения.

Вы должны знать, сколько растровых изображений в настоящее время видно, чтобы перерабатывать все остальное.

Также полезный трюк, когдаВы кодируете изображение (сначала вы должны загрузить его в кеш), сделайте это с помощью fileDescriptor

BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
o2.inPurgeable = true;
o2.inTempStorage = new byte[16 * 1024];
o2.inDither = true;
o2.inInputShareable = true; 

FileInputStream fs = null;
try {
    fs = new FileInputStream(f);
    } catch (FileNotFoundException e) {
   e.printStackTrace();
}

if (fs != null) {
    Bitmap b = BitmapFactory.decodeFileDescriptor(fs.getFD(),null, o2);
  }

Но если вы все делаете правильно, вам не нужен fileDescriptor (который работает медленнее)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...