Пикассо загружается в неправильное изображение при использовании шаблона владельца

Я пытаюсь использовать библиотеку Picasso для загрузки внешних изображений в строки в ListView. У меня есть пользовательский ArrayAdapter следующим образом:

public class RevisedBusinessesAdapter extends ArrayAdapter<HashMap<String, String>> {

    Context context;
    int layoutResourceId;
    ArrayList<HashMap<String, String>> data = null;

    public RevisedBusinessesAdapter(Context context, int layoutResourceId,  ArrayList<HashMap<String, String>> data) {
        super(context, layoutResourceId, data);
        this.layoutResourceId = layoutResourceId;
        this.context = context;
        this.data = data;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View row = convertView;
        RevisedBusinessHolder holder = null;

        if (row == null) {
            LayoutInflater inflater = ((Activity) context).getLayoutInflater();
            row = inflater.inflate(layoutResourceId, parent, false);
            holder = new RevisedBusinessHolder();
            holder.ivLogo = (ImageView) row.findViewById(R.id.ivBusinessLogo);
            row.setTag(holder);
        } else {
            holder = (RevisedBusinessHolder) row.getTag();
        }

        HashMap<String, String> business = data.get(position);

        String strLogoURL = business.get("logoURL");
        if (null != strLogoURL && !"".equals(strLogoURL)) {
            Picasso.with(this.context).load(strLogoURL).into(holder.ivLogo);        
        }

        return row;
    }

    static class RevisedBusinessHolder {
        ImageView ivLogo;
    }
}

где logoURL - это URL-адрес удаленного изображения; если не указано, ivBusinessLogo имеет локальный набор src, и это показано вместо этого. Когда я быстро прокручиваю, Picasso загружает изображение в неправильное ImageView, и я заканчиваю его несколькими копиями в списке.

Ответ на этот предполагает добавить

Picasso.with(context).cancelRequest(holder.ivLogo);

до существующего вызова Пикассо, но это не имеет никакого значения. Если я удалю проверку row == null и всегда создаю новое представление, оно работает нормально. В полной версии этого, однако, есть также четыре текстовых изображения и пять других изображений (маленькие значки, загруженные из локальных ресурсов, а не через Picasso), которые необходимо обновлять в каждом getView.

Есть ли способ сделать эту работу с шаблоном View Holder Документация по Android рекомендует?

Ответ 1

Вы всегда должны вызывать Picasso, даже если ваш URL null. Таким образом, он знает, что изображение было переработано.

Удалить этот оператор if:

if (null != strLogoURL && !"".equals(strLogoURL)) {

Вы также должны рассмотреть возможность использования образа-заполнителя или изображения с ошибкой, чтобы что-то отображалось, когда нет URL-адреса.

Если вы настаиваете на сохранении инструкции if (но вы этого не должны!), вам нужно сказать Пикассо, что просмотр изображения был переработан, вызвав cancelRequest:

Picasso.with(this.context).cancelRequest(holder.ivLogo);

Ответ 2

Установленный по умолчанию набор атрибутов src в layout.xml(в ImageView) переопределяется последним кэшированным файлом dowload, если текущий элемент не имеет изображения для загрузки с URL-адреса.

Вы должны вручную установить по умолчанию для itens, у которых нет атрибута изображения:

try {
     Picasso.with(activity.getApplicationContext()).load(customer.getImage().getPath()).placeholder(R.drawable.image_placeholder)
                .error(R.drawable.image_placeholder).into(imageView);
    }
catch (Exception e) {
       imageView.setImageResource(R.drawable.default_customer_icon);
       // this set the default img source if the path provided in .load is null or some error happened on download.
    }

Ответ 3

У меня такая же проблема и исправлена. Пожалуйста, рассмотрите параметр convertView в методе getView

convertView - это старый вид для повторного использования, если это возможно. Примечание. Вы должны проверить что перед просмотром это представление не имеет значения null и соответствующего типа. Если невозможно преобразовать это представление для отображения правильных данных, этот метод может создать новое представление.

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

if (row == null) {
    LayoutInflater inflater = ((Activity) context).getLayoutInflater();
    row = inflater.inflate(layoutResourceId, parent, false);
    holder = new RevisedBusinessHolder();
    ImageVIew ivLogo = (ImageView) row.findViewById(R.id.ivBusinessLogo);
    Picasso.with(this.context).load("Your Image URL").into(holder.ivLogo);
    row.setTag(holder);
}

Ответ 4

Добавьте инструкцию else после оператора Picasso.with(). load(). в(). Добавьте else holder.ivLogo.setImageBitmap(null);. Или используйте растровое изображение заполнителя.

Увидев решение Octa George, лучше всегда выполнять holder.ivLogo.setImageBitmap(placeholderbitmap); перед вызовом Picasso. В противном случае, когда Пикассо "не спешит", вы сначала увидите неправильное переработанное изображение.