Кэширование гифок в fresco

Я пытаюсь сделать recyclerview с гифками. Все показывает отлично, но fresco не кэширует гифки. После прокрутки ресайклера вниз и снова прокрутки вверх гифки загружаются снова. Я предположил, что они должны кэшироваться и загружаться немного быстрее. Ранее я использовал библиотеку ION. Загрузка была быстрее и не было проблем с кешем. Мне пришлось заменить библиотеку, потому что у нее возникли проблемы с декодированием gif, описанные здесь. Текущее решение выглядит так:

//for default initial in application class 

Fresco.initialize(this);
//I have also tried to change DiskCacheConfig and ImagePipelineConfig params. 
//Without any positive result

//for recyclerview on onBindViewHolder    
GenericDraweeHierarchy hierarchy = holder.draweeView.getHierarchy();
Uri uri = Uri.parse(path);
hierarchy.setPlaceholderImage(R.drawable.img_bg);
Logger.e(check(uri) + " " + uri.toString());
DraweeController controller = Fresco.newDraweeControllerBuilder().setUri(uri)
            .setAutoPlayAnimations(true).build();
    holder.draweeView.setController(controller);

//for method which show cached uri images in imagepipeline
public static boolean check(Uri uri) {
    ImagePipeline imagePipeline = Fresco.getImagePipeline();
    return imagePipeline.isInBitmapMemoryCache(uri);
}
//... all the time log shows "false + gif url"

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

редактировать: это похоже на анимацию кеша фрески, потому что приведенный ниже метод возвращает true для перезагруженных GIF-файлов.

public static boolean isImageDownloaded(Uri loadUri) {
    if (loadUri == null) {
        return false;
    }
    CacheKey cacheKey = DefaultCacheKeyFactory.getInstance()
            .getEncodedCacheKey(ImageRequest.fromUri(loadUri));
    return ImagePipelineFactory.getInstance().getMainDiskStorageCache().hasKey(cacheKey)
            || ImagePipelineFactory.getInstance().getSmallImageDiskStorageCache()
                    .hasKey(cacheKey);
}

person Nihilus13    schedule 26.01.2016    source источник


Ответы (3)


Чтобы было немного понятнее, у Fresco есть 3 уровня кеша:

  • DiskCache — сохраняет файлы изображений в их исходном формате. (Если быть точным, если в версии Android, которая не полностью поддерживает изображения webp, они могут быть перекодированы в другой формат перед сохранением.)
  • EncodedMemoryCache — кэш изображений в памяти в исходном закодированном формате. (Изображение сохраняется как байтовый массив исходных байтов, поскольку они хранятся на диске + некоторые дополнительные метаданные.)
  • BitmapMemoryCache — кеш в памяти, состоящий в основном из растровых изображений Android. Растровые изображения представляют собой декодированные изображения, и каждый пиксель занимает 32 бита, что значительно больше, чем требуется при кодировании.

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

Теперь вернемся к анимированным изображениям. Это известное ограничение. Анимированные изображения не кэшируются в их декодированной форме, потому что это исчерпает кеш растрового изображения (просто умножьте число_кадров * ширина * высота * 32bpp), и одно анимированное изображение может вытеснить любое другое изображение в кеше. Вместо этого они декодируются по запросу, и только пара кадров, которые должны быть отображены следующими, хранятся в недолговечном кеше.

У нас есть некоторые планы по улучшению анимации, хотя я не могу дать никаких оценок времени.

person plamenko    schedule 27.01.2016
comment
Я просто хочу знать, как кэшировать и показывать первый кадр гифки. - person Allen Vork; 18.05.2016
comment
Вероятно, вам следует уточнить в исходном вопросе, что вас интересует только первый кадр. - person plamenko; 18.05.2016

Я столкнулся с той же проблемой: кажется, что Fresco правильно кэширует изображения в формате gif, но на самом деле требуется время для декодирования и воспроизведения анимации каждый раз, когда вы прокручиваете RecyclerView или любое другое представление, которое вы используете. Однако, если вы используете изображение в формате gif без анимации, изображение в формате gif не «перезагружается» при прокрутке представления.

Поскольку у меня есть контроль над изображениями, отображаемыми внутри моего приложения. Я создаю 2 версии изображений gif на своем сервере, первая без анимации для отображения внутри RecyclerView/ListView, а другая для отображения внутри действия «Просмотрщик мультимедиа», когда пользователь щелкает элемент в списке.

person McHeimech    schedule 27.01.2016
comment
Это не удовлетворяющее решение. Я должен показать автоматически запускаемую сетку GIF. Когда вы посмотрите на приложение GIF Keyboard, вы увидите список/сетку гифок с анимацией автозапуска. Он плавно прокручивается с приемлемым поведением кэша. Их решение должно быть соответствующим. - person Nihilus13; 27.01.2016
comment
Должно быть уместно, но, к сожалению, я не могу понять, как они добились эффективного кеша и плавной прокрутки. - person Nihilus13; 27.01.2016
comment
Я использую fresco для загрузки gif, а не для его анимации. При прокрутке я все еще получаю проблему - person Allen Vork; 22.04.2016
comment
@McHaimech, ты нашел способ решить две версии гифки? - person Paraneetharan Saravanaperumal; 27.06.2016
comment
setAutoPlayAnimations(false) — хорошая идея, чтобы не декодировать GIF. возможно, миниатюра первого кадра кэшируется. это правда @AllenVork - person Paraneetharan Saravanaperumal; 27.06.2016
comment
@Nihilus13 GIF-клавиатура с использованием glide, а не fresco - person Paraneetharan Saravanaperumal; 27.06.2016
comment
@ParaSara setAutoPlayAnimations(false) не будет решением. Я упомянул выше, что использую fresco для загрузки gif, а не для его анимации, что означает, что я уже установил для него значение false. Fresco не получит первый кадр gif, но полностью декодирует gif для показа. - person Allen Vork; 27.06.2016
comment
@AllenVork запрошено, но еще не сделано: github.com/facebook/fresco/issues/714< /а> - person Paraneetharan Saravanaperumal; 28.06.2016
comment
@ParaSara, честно говоря, я не пошел дальше этого, так как использую предложенное решение в своем ответе. - person McHeimech; 28.06.2016

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

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

        ImageDecodeOptionsBuilder b = new ImageDecodeOptionsBuilder();
        b.setForceStaticImage(true);
        ImageDecodeOptions imageDecodeOptions=new ImageDecodeOptions(b);
        ImageRequest request =  ImageRequestBuilder.newBuilderWithSource(animatedGifUri).setImageDecodeOptions(imageDecodeOptions).setLocalThumbnailPreviewsEnabled(true).build();
person Paraneetharan Saravanaperumal    schedule 07.07.2016