web-dev-qa-db-fra.com

Adaptateur RecyclerView affichant des images erronées

J'ai un adaptateur RecyclerView qui ressemble à ceci:

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();
    }

}

Cependant, certains éléments de RecyclerView affichent des images alors qu'elles ne devraient pas l'être. Comment puis-je empêcher cela de se produire?

Je fais la vérification if (numImages > 0) { dans onBindViewHolder(), mais cela ne l'empêche pas toujours d'afficher des images pour des éléments qui ne devraient pas en avoir.

13
user5578746

Vous devez définir imageView.setImageDrawable (null) In onBindViewHolder() avant de définir l’image en mode plané.

La définition d’image drawable sur null corrige le problème.

J'espère que ça aide!

10
Prashant Solanki

Le problème est dans onBindViewHolder, ici:

    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);
    }

Si numImages est égal à 0, vous autorisez simplement la charge précédemment lancée dans la vue que vous réutilisez à continuer. Une fois l'opération terminée, l'ancienne image sera toujours chargée dans votre vue. Pour éviter cela, dites à Glide d'annuler le chargement précédent en appelant clear:

   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);
    }

Lorsque vous appelez into(), Glide se charge d’annuler l’ancienne charge. Si vous n'appelez pas into(), vous devez appeler clear() vous-même. 

Chaque appel à onBindViewHolder doit inclure un appel load() ou un appel clear().

10
Sam Judd

J'ai également eu des problèmes avec RecyclerView montrant des images fausses. Cela est dû au fait que RecyclerView ne gonfle pas la vue pour chaque nouvel élément de la liste: les éléments de la liste sont en cours de recyclage. 

En recyclant les points de vue, nous pouvons vraiment comprendre clonage vues. Une vue clonée peut avoir un ensemble d'images issu de l'interaction précédente. 

Ceci est particulièrement juste si vous utilisez Picasso, Glide ou une autre bibliothèque pour le chargement asynchrone. Ces bibliothèques contiennent des références à un ImageView et définissent une image sur cette référence lors du chargement de l'image. 

Au moment où l'image est chargée, la vue d'élément peut avoir été clonée et l'image va être définie sur le mauvais clone .

En résumé, j'ai résolu ce problème en empêchant RecyclerView de cloner les vues de mes éléments:

setIsRecyclable(false)in dans le constructeur ViewHolder.

Maintenant, RecyclerView fonctionne un peu plus lentement, mais au moins, les images sont correctement définies.

Sinon, vous pouvez charger l'image dans onViewRecycled(ViewHolder holde)

9

Le problème ici est que, comme vous travaillez avec des vues qui vont être recyclées, vous devez gérer tous les scénarios possibles au moment de lier votre vue.

Par exemple, si vous ajoutez ImageView à LinearLayout à la position 0 de la source de données, si la position 4 ne remplit pas la condition, l'affichage sera probablement ajouté lors de la liaison à la position 0.

Vous pouvez ajouter le contenu du contenu R.layout.images dans votre 

R.layout.message_layout layout's R.id.placeholder et affichage/masquage de l'espace réservé en fonction du cas.

Ainsi, votre méthode onBindViewHolder serait quelque chose comme:

@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);
        }
    }
3
mmark

J'ai eu le même problème et je l'ai corrigé comme ceci:

OBJECTIF: 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));
    }
}
0
Hadi Note

J'ai également eu le même problème et fini avec la solution ci-dessous et cela fonctionne très bien pour moi ..

Avoir la main sur cette solution pourrait être un travail pour vous aussi (Mettez le code ci-dessous dans votre classe d'adaptateur) - 

Si vous utilisez Kotlin -  

override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getItemViewType(position: Int): Int {
        return position
    }

Si vous utilisez Java -  

 @Override
    public long getItemId(int position) {
        return position;
    }

@Override
    public int getItemViewType(int position) {
        return position;
    }
0
Bajrang Hudda