Android - проблема с отложенной загрузкой изображений в ListView - PullRequest
6 голосов
/ 11 сентября 2009

Это очень распространенный сценарий: отображение изображений в ListView, которые необходимо загрузить из Интернета.

Прямо сейчас у меня есть собственный подкласс ArrayAdapter, который я использую для ListView. В моей реализации getView () ArrayAdapter я создал отдельный поток для загрузки изображения. После завершения загрузки, он ищет соответствующий ImageView и устанавливает изображение с помощью ImageView.setImageDrawable (). Таким образом, решение, которое я использовал, похоже на это: Ленивая загрузка изображений в ListView

Проблема, с которой я столкнулся, заключается в том, что как только я выполняю вызов setImageDrawable () в ImageView, ListView каким-то образом обновляет все видимые в данный момент строки в списке! В результате получается бесконечный цикл:

  1. getView () называется
  2. создается нить для загрузки изображения
  3. изображение загружено; setImageDrawable () вызывается для ImageView
  4. ListView по какой-то причине подхватывает его и обновляет
  5. Для обновления ListView, getView () вызывается для каждой видимой строки, поэтому мы возвращаемся к шагу 1 и все повторяется

Итак, насколько я вижу, решение, предложенное в разделе «Android - Как сделать ленивую загрузку изображений в ListView» (см. Ссылку выше), просто не работает. Может показаться, что это так, но он будет работать очень медленно, поскольку в фоновом режиме он продолжает перезагружать видимые в данный момент строки.

Кто-нибудь сталкивался с этим раньше и / или имел решение для этого?

Ответы [ 4 ]

3 голосов
/ 07 марта 2012

У меня была такая же проблема.

После почти 2 дней тяжелой отладки / оптимизации и попыток выяснить, почему мой getView() снова и снова вызывается для всех представлений при использовании setImageBitmap() в строке, я нашел грязное решение:

1) Расширьте пользовательский ImageView, который вы используете для всех изображений в вашем списке

2) при этом ImageView перезаписать метод

@Override
public void requestLayout()
{ 
  return; 
}

3) Грязно, но у меня это работает

4) Прибыль;)

3 голосов
/ 23 марта 2011

Я использовал код по следующей ссылке: другой вопрос stackoverflow

Я внес небольшие изменения, чтобы решить проблему повторного просмотра. Я установил URL-адрес изображения в тег тега просмотра изображения в адаптере. Следующий код содержит мое решение, которое решает проблему утилизации:

public void fetchDrawableOnThread(final String urlString, final ImageView imageView,Drawable drw) {

    imageView.setImageDrawable(drw);//drw is default image
    if (drawableMap.containsKey(urlString)) {
        if(imageView.getTag().toString().equals(urlString))
        {
            imageView.setImageBitmap(drawableMap.get(urlString));
            imageView.invalidate();
            return;
        }

    }

    final Handler handler = new Handler() {
        @Override
        public void handleMessage(Message message) {
            BitmapWrapper wrapper = (BitmapWrapper)message.obj;
            if(wrapper.imageurl.equals(imageView.getTag().toString()))
            {
                imageView.setImageBitmap((Bitmap)wrapper.bitmap);
                imageView.invalidate();
            }

        }
    };

    Thread thread = new Thread() {
        @Override
        public void run() {
            //TODO : set imageView to a "pending" image

            Bitmap drawable = fetchDrawable(urlString);
            BitmapWrapper wrapper = new BitmapWrapper();
            wrapper.bitmap = drawable;
            wrapper.imageurl = urlString;
            Message message = handler.obtainMessage(1, wrapper);
            handler.sendMessage(message);
        }
    };
    thread.start();
}


    public class BitmapWrapper
{
    public Bitmap bitmap;
    public String imageurl;
}
2 голосов
/ 11 сентября 2009

У меня есть ThumbnailAdapter , который завершает весь этот шаблон, который может помочь.

2 голосов
/ 11 сентября 2009

В связанном решении fetchDrawableOnThread() следует вызывать только в том случае, если представление еще не имеет правильной отрисовки.

Вид не может отображаться, если getDrawable() возвращает ноль.

Если вы повторно используете слоты, вам нужно идти дальше и управлять состоянием. Если в ваших представлениях есть переменная-член, хранящая URL-адрес, и логическое значение, указывающее, загружен ли он, легко узнать, например, вызывать fetchDrawableOnThread() или нет.

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

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

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