Android Volley — отмена запроса NetworkImageView в базовом адаптере

Как следует из названия, я использую BaseAdapter для отображения элементов в ListView. Очевидно, что ListView будет повторно использовать представления, включая TextView и NetworkImageView.

Предполагая, что 3 элемента могут отображаться одновременно, NetworkImageView будет повторно использоваться для элементов с индексом: 1, 4, 7, ....

В зависимости от того, что отображается, NetworkImageView будет либо:

  1. запрашивать изображение из Сети и отображать его,
  2. отображать кэшированное растровое изображение,
  3. или отображать локальный доступный ресурс.

Элементы 2 и 3 работают нормально, однако в сценарии 1, допустим, мы отображаем элемент с индексом 4 из сети, и пользователь прокручивает элемент 7 до загрузки 4, и это локальный ресурс, мы отображаем локальный ресурс. Однако наш запрос сетевого образа может быть только что завершен, поэтому мы в конечном итоге отображаем неправильное изображение.

Как я могу обеспечить правильное (ожидаемое) поведение?


person StackOverflowed    schedule 18.08.2013    source источник


Ответы (3)


Ответ от @Snicolas точен, но ему не хватает некоторых указаний о том, как это сделать. Так вот.

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

Один из простых способов добиться этого — сделать ImageContainer, который вы можете получить при запросе загрузки изображения, частью ViewHolder/RowWrapper адаптера. Если вы еще не используете этот шаблон, вам следует это сделать. Существует множество примеров, в том числе хороший разговор о вводе-выводе.

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

ImageListener listener = ImageLoader.getImageListener(holder.imageview, defaultImageResId, errorImageResId);
holder.mImageContainer = ImageLoader.get(url, listener);

В следующий раз, когда переработанная строка появится в методе getView() адаптера, вы можете получить от нее свой держатель и проверить, имеет ли он набор ImageContainer. Может применяться один из следующих 3 сценариев:

  • ImageContainer нет, что означает, что вы можете сделать новый запрос на изображение.
  • Существует ImageContainer, и URL-адрес, который он загружает, такой же, как и для данных новой строки. В этом случае вам не нужно ничего делать, так как он уже загружает изображение, которое вам нужно.
  • Существует ImageContainer, но URL-адрес, который он загружает, отличается от данных новой строки. В этом случае отмените запрос и создайте новый для данных текущей строки.

Если хотите, вы можете переместить часть этой логики, реализовав расширение BaseAdapter AbsListView.RecyclerListener (и установите адаптер в качестве прослушивателя повторного использования для ListView или GridView). Метод onMovedToScrapHeap(View view) передается только что переработанному представлению, что означает, что вы можете отменить любые ожидающие запросы изображений.

person MH.    schedule 18.08.2013
comment
Ответ @Pork правильный, но это очень полезная информация, когда не используется NetworkImageView. Также хорошая информация об использовании AbsListView.RecyclerListener, если кому-то нужен дополнительный контроль над представлениями. +1 - person pjco; 29.08.2013
comment
Спасибо за ответ, у меня только сомнения, как можно отменить запросы, сделанные методом get из ImageLoader? вы не можете добавить тег к этим запросам, что вам нужно, чтобы отменить запрос. - person vantesllar; 23.09.2014
comment
Неважно, я видел, что класс ImageContainer имеет собственный метод для отмены запроса, который предназначен для хранения изображения. - person vantesllar; 23.09.2014

Вам не нужно ничего применять, если вы используете предоставленный NetworkImageView.

NetworkImageView определяет, когда он был переработан, и автоматически отменяет запрос.

person Pork 'n' Bunny    schedule 20.08.2013
comment
К сожалению, на самом деле это не ответ на вопрос. В адаптере для чего-то вроде ListView соответствующее представление перерабатывается и поэтому никогда не будет отсоединяться. - person StackOverflowed; 09.10.2013
comment
Можете ли вы показать мне, где это происходит, если вы не возражаете? Одна вещь с Volley заключается в том, что нет выпусков или номеров версий, так что, возможно, я просто использую более старую версию. - person StackOverflowed; 09.10.2013
comment
Когда представление перерабатывается, вы должны установить NetworkImageView с новым значением в getView вашего адаптера. В этот момент NetworkImageView уничтожит старый запрос. Это происходит как часть процесса повторного использования, поэтому ситуация, описанная OP, просто никогда не возникнет, если они используют NetworkImageView. Вы правы, утверждая, что NetworkImageView не отменяет запрос при отсоединении от списка, только после его повторной обработки запрос останавливается. Я обновил свой ответ, спасибо. - person Pork 'n' Bunny; 09.10.2013

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

Были ли у вас здесь альтернативы, такие как:

person Snicolas    schedule 18.08.2013