Асинхронная загрузка растровых изображений в адаптер, с акцентом на Bitmap.recycle () - PullRequest
7 голосов
/ 23 ноября 2011

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

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

  1. Нет дублирования загрузчиков или растровых изображений
  2. Отмена загрузки / назначения изображений, которые больше не нужны или могут быть автоматически удалены (SoftReference и т. Д.)
  3. Примечание: адаптер может иметь несколько представлений для одного и того же идентификатора (вызовы getView (0) очень часты)
  4. Примечание: нет никакой гарантии, что представление не будет потеряно вместо повторного использования (рассмотрите изменение размера или фильтрации List / GridView по тексту)
  5. Разделение представлений и данных / логики (насколько это возможно)
  6. Не запускается отдельная тема для каждой загрузки (заметное замедление пользовательского интерфейса). Используйте очередь / стек (BlockingQueue?) И пул потоков, или еще что-нибудь .... но нужно прекратить это, если действие остановлено.
  7. Очистка растровых изображений, достаточно удаленных от текущей позиции в списке / сетке, предпочтительно только тогда, когда требуется память
  8. Вызов recycle () для каждого битмапа, который должен быть отброшен.
  9. Примечание: внешняя память может быть недоступна (вообще или постоянно), и, если используется, должна быть очищена (только из загруженных здесь изображений) как можно скорее (рассмотрите уничтожение / восстановление активности с помощью Android)
  10. Примечание: данные могут быть изменены: записи удалены (множественный выбор и удаление) и добавлены (в фоновом потоке). Уже загруженные растровые изображения должны сохраняться, пока записи, с которыми они связаны, все еще существуют.
  11. setTextFilterEnabled (true) (если основано на механизме ArrayAdapter, повлияет на индексы массива)
  12. Используется в ExpandableList (влияет на порядок отображения миниатюр)
  13. (необязательно), когда битмап загружен, обновите ТОЛЬКО соответствующий ImageView (элементы списка могут быть очень сложными)

Пожалуйста, не публикуйте ответы по отдельным пунктам. Моя проблема в том, что чем больше мы фокусируемся на одних аспектах, тем более размытыми становятся другие, Гейзенберговские .
Каждый добавляет измерение сложности, особенно Bitmap.recycle, который необходимо вызывать во время операции и при уничтожении действия (обратите внимание, что onDestroy, даже onStop, может не вызываться).
Это также исключает возможность использования SoftReferences .
Это необходимо , или я получаю OutOfMemoryError даже после любого количества gc, sleep (20 с, даже), yield и огромных выделений массива в try-catch (для принудительного управления контролируемым OutOfMemory) после обнуления Bitmap.
Я пересматриваю Битовые карты уже.

Ответы [ 2 ]

2 голосов
/ 14 декабря 2011

Проверьте этот пример.Так как его использует Google, и я также использую ту же логику, чтобы избежать ошибки OutOfMemory.

http://developer.android.com/resources/samples/XmlAdapters/index.html

В основном этот ImageDownlaoder является вашим ответом (поскольку он охватывает большинство ваших требований), некоторые из которых вы также можете реализовать в этом.

http://developer.android.com/resources/samples/XmlAdapters/src/com/example/android/xmladapters/ImageDownloader.html

0 голосов
/ 05 февраля 2013

В конце концов, я решил полностью игнорировать ошибку утилизации.он просто добавляет слой невозможных трудностей поверх управляемого процесса.
Без этого бремени (просто прекращая показ изображений на адаптерах и т. д.), я создал менеджер, использующий Map<String, SoftReference<Bitmap>> для хранения загруженных растровых изображений под URL-адресами.
Кроме того, 2-4 AsyncTasks (использующие как doInBackground, так и onProgressUpdate; остановлены добавлением специальных заданий, которые выдают InterruptedException), берущие задания из LinkedBlockingDeque<WeakReference<DownloadingJob>>, поддерживаемого WeakHashMap<Object, Set<DownloadingJob>>.
Deque (код LinkedBlockingDeque, скопированный для использованияв более раннем API) - это очередь, в которую могут уходить задания, если они больше не нужны.В качестве ключей на карте есть создатели заданий, поэтому, если адаптер требует загрузки, а затем удаляется, он удаляется с карты и, как следствие, все его задания исчезают из очереди.

Задание будет, если изображение уже присутствует, вернуться синхронно.он также может содержать набор данных, который может идентифицировать, какое положение в AdapterView это касается.

Кэширование также выполняется на SD-карте, , если доступно , под URLE-кодированными именами.(очищено частично, начиная с самого старого, при запуске приложения и / или с помощью deleteOnExit ()
запросы включают в себя «If-Modified-Since», если у нас есть кэшированная версия, для проверки обновлений.

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

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