2015-11-20 4 views
11

у меня есть адаптер RecyclerView который выглядит следующим образом:RecyclerView адаптер показывает неправильные изображения

public class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> { 

    private static Context context; 
    private List<Message> mDataset; 

    public RecyclerAdapter(Context context, List<Message> myDataset) { 
     this.context = context; 
     this.mDataset = myDataset; 
    } 

    public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener, View.OnClickListener { 
     public TextView title; 
     public LinearLayout placeholder; 

     public ViewHolder(View view) { 
      super(view); 
      view.setOnCreateContextMenuListener(this); 

      title = (TextView) view.findViewById(R.id.title); 
      placeholder = (LinearLayout) view.findViewById(R.id.placeholder); 
     } 
    } 

    @Override 
    public RecyclerAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 
     View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.message_layout, parent, false); 
     ViewHolder vh = new ViewHolder((LinearLayout) view); 

     return vh; 
    } 

    @Override 
    public void onBindViewHolder(ViewHolder holder, int position) { 
     Message item = mDataset.get(position); 

     holder.title.setText(item.getTitle()); 

     int numImages = item.getImages().size(); 

     if (numImages > 0) { 
      View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false); 
      ImageView image = (ImageView) test.findViewById(R.id.image); 
      Glide.with(context) 
       .load("http://www.website.com/test.png") 
       .fitCenter() 
       .into(image); 
      holder.placeholder.addView(test); 
     } 
    } 

    @Override 
    public int getItemCount() { 
     return mDataset.size(); 
    } 

} 

Однако, некоторые из элементов в RecyclerView показывают изображения, когда они не должны быть. Как я могу остановить это?

Я делаю чек if (numImages > 0) { в onBindViewHolder(), но это все еще не останавливает его от показа изображений для предметов, которые не должны иметь изображений.

+2

Если вы получили ответ, пожалуйста, одобрить это –

ответ

2

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

Например, если вы добавляете ImageView в LinearLayout в положение 0 источника данных, то, если позиция 4 не удовлетворяет условию, его вид, скорее всего, будет иметь ImageView, добавленный при позиции привязки 0 .

Вы можете добавить содержимое контента R.layout.images внутри вашего

R.layout.message_layout компоновщика R.id.placeholder и показать/скрыть заполнитель в зависимости от случая.

Таким образом, ваш метод onBindViewHolder будет что-то вроде:

@Override 
    public void onBindViewHolder(ViewHolder holder, int position) { 
     Message item = mDataset.get(position); 

     holder.title.setText(item.getTitle()); 

     int numImages = item.getImages().size(); 

     if (numImages > 0) { 
      holder.placeholder.setVisivility(View.VISIBLE); 
      ImageView image = (ImageView)holder.placeholder.findViewById(R.id.image); 
      Glide.with(context) 
       .load("http://www.website.com/test.png") 
       .fitCenter() 
       .into(image); 
     }else{ 
      holder.placeholder.setVisibility(View.INVISIBLE); 
     } 
    } 
+0

Если я просто сделаю 'placeholder' невидимым, разве это не значит, что он по-прежнему загружает изображение, но скрывает его? – user5578746

+0

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

+0

Да, но для производительности я бы тоже не загружал изображение без необходимости. Вы также пропустили линию, где я раздуваю другой макет, что означает, что он раздувает макет, а также загружает изображение, а затем скрывает его. – user5578746

8

Вы должны установить imageView.setImageDrawable (null) В onBindViewHolder() перед установкой изображения с использованием скольжению.

Установка изображения, предназначенного для устранения ошибки, устраняет проблему.

Надеюсь, это поможет!

+2

, но он немного замедляет прокрутку, когда он снова загружает изображение. – Bharatesh

+0

Спасибо, работал на меня .. и быстрая прокрутка медленнее. ожидаемый результат заключается в том, чтобы не потерять изображения ... и так далее ... –

+0

У меня есть небольшое сомнение, предположим, что когда экран впервые загружает, у него есть изображение, а затем на некоторые обновления соответственно, это изображение изменяется, и в этот момент я должен установить его ноль? Пожалуйста, уточните мои сомнения. Заранее спасибо. :) –

7

Проблема заключается в onBindViewHolder, здесь:

if (numImages > 0) { 
     View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false); 
     ImageView image = (ImageView) test.findViewById(R.id.image); 
     Glide.with(context) 
      .load("http://www.website.com/test.png") 
      .fitCenter() 
      .into(image); 
     holder.placeholder.addView(test); 
    } 

Если numImages равно 0, вы просто позволяя ранее начала нагрузки в поле зрения вы повторного использования, чтобы продолжить. Когда он закончится, он все равно загрузит старое изображение в ваше представление. Чтобы предотвратить это, скажите Glide, чтобы отменить предыдущую загрузку по телефону ясно:

if (numImages > 0) { 
     View test = LayoutInflater.from(holder.placeholder.getContext()).inflate(R.layout.images, holder.placeholder, false); 
     ImageView image = (ImageView) test.findViewById(R.id.image); 
     Glide.with(context) 
      .load("http://www.website.com/test.png") 
      .fitCenter() 
      .into(image); 
     holder.placeholder.addView(test); 
    } else { 
     Glide.clear(image); 
    } 

Когда вы звоните into(), Glide ручки отменяя старый груз для вас. Если вы не позвоните по телефону into(), вы должны позвонить по телефону clear().

Каждый вызов onBindViewHolder должен включать либо вызов load(), либо звонок clear().

+0

с использованием 'clear()' - лучший способ обработки ожидающих запросов, вызванных переработкой –

+0

, вы добавляете основной пункт в какую-то тему здесь. Есть куча тем вокруг recyclerview перепутали элементы во время прокрутки. Я думаю, что это решение для этой ситуации в некоторых случаях. во всяком случае, большое спасибо. – Setmax

+0

Кажется, вы работаете с Bumptech. Это работает как магия. Спасибо – Idee

8

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

Просмотреть краткое представление клонирование просмотров. Клонированный вид может иметь изображение, установленное в предыдущем взаимодействии.

Это особенно справедливо, если вы используете Picasso, Glide или какую-либо другую lib для асинхронной загрузки.Эти библиотеки содержат ссылку на ImageView и устанавливают изображение при этом повторении при загрузке изображения.

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

Чтобы сделать длинную историю короткой, я решил эту проблему путем ограничения RecyclerView от клонирования мои представлений элементов:

setIsRecyclable(false) в ViewHolder конструктору.

Теперь RecyclerView работает немного медленнее, но по крайней мере изображения установлены правильно.

Или Cansel загрузка изображения в onViewRecycled(ViewHolder holde)

+0

Согласно документации Android SDK: вызов setIsRecyclabe (false) должен всегда соответствовать более позднему вызову setIsRecyclable (true)). Пары вызовов могут быть вложенными, так как состояние внутренне подсчитано. [RecyclerView # setIsRecycable] (https://developer.android.com/reference/android/support/v7/widget/RecyclerView.ViewHolder.html#setIsRecyclable (булево)) Ваше решение, к сожалению, не рекомендуется. – Garytech

+0

Это не рекомендуется специально для очень больших и тяжелых наборов данных. Ответ Прашант Соланки - лучший вариант. –

0

Я была такая же проблема, и я установил его так:

ЦЕЛЬ: onViewAttachedToWindow

@Override 
public void onViewAttachedToWindow(Holder holder) { 
    super.onViewAttachedToWindow(holder); 
    StructAllItems sfi = mArrayList.get(position); 
    if (!sfi.getPicHayatParking().isEmpty()) { 
     holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicHayatParking() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); 
    } 
    if (!sfi.getPicSleepRoom().isEmpty()) { 
     holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicSleepRoom() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); 
    } 
    if (!sfi.getPicSalonPazirayi().isEmpty()) { 
     holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicSalonPazirayi() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); 
    } 
    if (!sfi.getPicNamayeStruct().isEmpty()) { 
     holder.viewFliperMelk.addSlider(new TextSliderView(mContext.getApplicationContext()).image(T.GET_MELK_IMAGE + '/' + sfi.getPicNamayeStruct() + ".jpg").setScaleType(BaseSliderView.ScaleType.CenterCrop)); 
    } 
} 
Смежные вопросы