Android - Хранение изображений, загруженных из Интернета - PullRequest
14 голосов
/ 13 января 2010

У меня возник вопрос, связанный с тем, следует ли (и как) хранить изображения, загруженные из Интернета. Допустим, я звоню в веб-сервис из моего приложения для Android. В этом веб-сервисе я получаю URL для изображения в Интернете. Я загружаю и показываю это изображение слева от элемента списка в ListView. У меня вопрос, какой метод я должен использовать для возможного хранения изображения? Должен ли я:

  1. Сохраните его на SDCard, проверив, существует ли он при создании ListView (при последующих запросах), и при необходимости повторно загрузите (при периодическом обновлении изображения в случае его изменения).
  2. Сохраните его в кеше с помощью Context.getCacheDir (), но, возможно, вам придется загружать его чаще, поскольку я не могу полагаться на изображение, оставшееся в кэше.
  3. Всегда загружайте его и никогда не сохраняйте изображение.

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

В качестве дополнительного вопроса, должен ли я сначала загрузить все изображения в свой ListView (и, возможно, заблокировать пользовательский интерфейс на некоторое время) или загрузить их асинхронно, но в то же время показывать графику-заполнитель (что может быть немного более уродливо) «)? Какой стандарт здесь?

Ответы [ 4 ]

21 голосов
/ 13 января 2010

О том, где хранить: Ответ зависит от того, что загружается и сколько. Тогда вы делаете выбор.

Например: если вы загружаете что-то временное, меньшее по количеству (меньше удаленных выборок) и по размеру (меньше памяти) и локальное для Activity, то вам следует рассмотреть возможность хранения изображений в памяти с помощью SoftReferences. SoftReferences может привести к повторным запросам, но поскольку количество элементов невелико, оно должно быть доступным.

Однако, если количество загружаемых элементов превышает определенный порог (то есть больше выборок и памяти), вам следует рассмотреть возможность сокращения выборок, а также потребления оперативной памяти путем их кэширования. Здесь вы можете выбрать сохранение их на SD-карте или во временном хранилище (каталоги кэша, локальные для приложения). Для элементов, которые являются небольшими и имеют значение только в контексте приложения (например, эскизы), пользователь в основном не будет использовать его вне вашего приложения. Таким образом, вы можете хранить такие вещи в каталоге кеша. Лучшая часть их использования заключается в том, что вам не нужно убирать беспорядок. Это обрабатывается автоматически. Это может привести к повторной загрузке.

Однако, если загруженные элементы имеют большой размер и могут стоять отдельно от контекста приложения, такого как изображения, видео, аудиоклипы, тогда SDcard должен быть вашим выбором. Вы также должны прочитать: Обработка больших растровых изображений, чтобы избежать ошибки OOM во время BitmapFactory.decodeStream (..)

Обратите внимание, что вы также можете проверить, может ли здесь помочь использование базы данных. См.

Некоторые соображения при ленивой загрузке элементов в ListView: Вы должны выполнить загрузку в фоновом режиме, а не блокировать поток пользовательского интерфейса. Следует рассмотреть возможность показа временного изображения во время загрузки элемента. Это очевидно во многих нативных приложениях. Пример реализации отложенной загрузки см. В этом . Кроме того, для больших списков вы можете реализовать шаблон SlowAdapter (проверьте демонстрацию API). Он в основном останавливается при прокрутке списка.

Примеры проектов, которые могут вам помочь:

В проекте Romain Guy's Shelves используется два уровня кэширования, в которых он использует кэш в памяти (HashMap, содержащий SoftReferences) и хранилище на SDCard. Просмотреть исходный код здесь

Есть также несколько библиотек с открытым исходным кодом, которые написал Марк Мерфи (CWAC) и DroidFu, которые могут помочь здесь.

Удачи!

3 голосов
/ 13 января 2010

Что касается вашего «побочного вопроса» - я думаю, что асинхронная загрузка их была бы предпочтительным поведением, особенно с учетом того, что вы должны учитывать, что в случае сетевых транзакций это может быть не просто «блокировка интерфейса на некоторое время» но "навсегда заблокировать пользовательский интерфейс" на случай, если он никогда не загрузится.

Однако, если вы считаете это поведение уродливым, вы можете установить таймер (1 или 2 секунды), который дает возможность загрузить несколько изображений, и если все они загружены или время таймера истекло, продолжайте и В любом случае покажите пользовательский интерфейс с изображениями-заполнителями, а остальные загрузятся асинхронно. Это был бы способ предотвратить постоянные блокировки в любом случае.

Что касается первой части вашего вопроса, я думаю, что она в некоторой степени зависит от контекста и типа отображаемых вами изображений. Тем не менее, с большинством веб-ресурсов, я думаю, # 2 будет предпочтительным подходом, так как вы, конечно, не хотите загружать несколько раз в одном сеансе, но вы, вероятно, тоже не хотите использовать постоянное хранилище.

1 голос
/ 22 августа 2010

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

Чтобы избежать этого, если мы говорим о WebImageView от droid-fu, вы можете изменить функцию ImageLoader.java initialize () на эту

    static int alive=-1;
   public static synchronized void initialize(Context context) {

        if (executor == null) {        
           executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);           
       }
        else if(alive==executor.getActiveCount()){
               executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(DEFAULT_POOL_SIZE);
           }
       alive=executor.getActiveCount();
       if (imageCache == null) {
           imageCache = new ImageCacheHope(context, 25, 5);
       }
   }
0 голосов
/ 12 февраля 2013

Я написал Android Image Manager, который прозрачно обрабатывает кэширование (память и диск). Код есть на Github https://github.com/felipecsl/Android-ImageManager

...