web-dev-qa-db-fra.com

Comment faire pour que RecyclerView arrête de recycler des positions définies?

Mon problème est le suivant: j'ai un flux vidéo en cours sur l'une des vues à l'intérieur de RecyclerView.

Lorsque l'utilisateur défile, la vue est recyclée et les autres caméras commencent leur propre diffusion sur ce visualiseur recyclé. C'est mauvais pour l'interface utilisateur car le processus de streaming prend quelques secondes pour démarrer.

Comment puis-je dire à RecyclerView: "Hey Recycler, s'il vous plaît, ne recyclez pas cette position exacte x et donnez cette position TOUJOURS le même viewholder que vous lui avez donné la première fois, au lieu d'un aléatoire "?

S'il vous plaît, quelqu'un m'aide = (

19
Daniel Oliveira

Dans votre méthode d'adaptateur getItemViewType(int position), affectez des valeurs uniques pour chaque vidéo, afin qu'elle renvoie toujours le même ViewHolder pour la même vidéo que vous le souhaitez.

  • renvoie un nombre positif unique comme type pour chaque type de vidéo (ici, j'ai utilisé la position de l'adaptateur comme clé unique)
  • renvoyer des nombres négatifs pour tous les éléments non vidéo. (rien de spécial ici, juste pour éviter les conflits avec les éléments vidéo, nous utilisons des nombres négatifs pour les éléments non vidéo)

J'espère que vous comprenez l'idée. à votre santé :)

    @Override
    public int getItemViewType(int position) {
        // Just as an example, return 0 or 2 depending on position
        // Note that unlike in ListView adapters, types don't have to be   contiguous
        if(dataList.get(position).isVideo()){
            return position;

        }else{
            return -1;//indicates general type, if you have more types other than video, you can use -1,-2,-3 and so on.
        }
    }

 @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         switch (viewType) {
             case -1:  View view1 = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.general_item, parent, false);
                     return new GeneralViewHolder(view1);
             default:View view2 = LayoutInflater.from(parent.getContext())
                    .inflate(R.layout.video_item, parent, false);
                     return new VideoViewHolder(view2);

         }
    }
14
Darish

Exécutez viewHolder.setIsRecyclable(false) sur le ViewHolder que vous souhaitez pas recyclé.

De documents de ViewHolder # setIsRecyclable (boolean) :

Informe le recycleur si cet article peut être recyclé. Les vues qui ne sont pas recyclables ne seront pas réutilisées pour d'autres éléments jusqu'à ce que setIsRecyclable () soit ultérieurement défini sur true.

Cela entraînera la création d'un seul ViewHolder.

public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    ...
    @Override
    public void onViewAttachedToWindow(final RecyclerView.ViewHolder holder) {
        if (holder instanceof VideoViewHolder) {
            holder.setIsRecyclable(false);
        }
        super.onViewAttachedToWindow(holder);
    }

    @Override
    public void onViewDetachedFromWindow(final RecyclerView.ViewHolder holder) {
        if (holder instanceof VideoViewHolder){
            holder.setIsRecyclable(true);
        }
        super.onViewDetachedFromWindow(holder);
    }
    ...
}
12
azizbekian

RecyclerView utilise une vue plusieurs fois, lorsqu'elle contient la liste qui ne s'affiche pas à l'écran à la fois (signifie qu'une liste contient une grande quantité d'éléments qui ne s'affiche pas à l'écran en même temps que vous devez faire défiler vers le haut et vers le bas). Lorsque l'utilisateur fait défiler la liste, les éléments hors écran sont réutilisés pour afficher les éléments de liste restants, ce qui est appelé recyclage.

Pour arrêter le recyclage des éléments, appelez cette méthode dans votre méthode onBindViewHolder:

viewHolder.setIsRecyclable(false);

Cette déclaration arrête le recyclage des vues.

Pour commencer à recycler les éléments, appelez cette méthode dans votre méthode onBindViewHolder:

viewHolder.setIsRecyclable(true);

J'espère que cela résoudra votre problème. Merci

3
Aman Goyal

Votre problème vient du spectateur lui-même. Les titulaires de vues font référence aux vues, contrairement à l'adaptateur. L'adaptateur conserve uniquement la collecte de données. Par conséquent, ajoutez un champ à la vue pour conserver une référence de l'élément de données que vous avez utilisé pour remplir la vue dans la vue. En d'autres termes:

public class SomeViewHolder extends RecyclerView.ViewHolder{

    private View view;
    private Data data;

    public SomeViewHolder(View itemView) {
        super(itemView);
        view = itemView;
    }

    public void bindData(Data data){
        view.setData(data);
        this.data = data;
    }

    public void setData(Data data){
       this.data = data;
    }


    public Data getData(){
        return data;
    }

    public View getView(){
        return view;
    }
}

Maintenant, le viewholder sait quel élément de l'adaptateur utilise. Par conséquent, lorsque vous remplacez la méthode de liaison dans l'adaptateur, vous pouvez vérifier si le titulaire a déjà lié certaines données et, si les données contiennent de la vidéo, vous pouvez éviter la liaison et définir de force une vue déjà chargée.

@Override
public void onBindViewHolder(SomeViewHolder holder, int position) {

    //videoViewData is a data field you have to put into the adapter.
    //videoView is a view field you have to put into the adapter.

    if(adapterData.get(position).equals(videoViewData)){
        holder.setView(videoView);
        holder.setData(adapterData.get(position));
    }else{
        holder.bindData(adapterData.get(position));
        if(adapterData.get(position).isVideo()){
            videoViewData = adapterData.get(position);
            videoView = holder.getView(); 
        }
    }

}

Enfin, vous devrez remplacer la méthode onViewRecycled dans l'adaptateur, donc, lorsqu'une vue contenant une vidéo est recyclée, vous pouvez obtenir la vue et la placer ailleurs.

public void onViewRecycled(SomeViewHolder holder){
    if(holder.getData().isVideo()){
        videoViewData = holder.getData().
        videoView = holder.getView();
        videoView.pauseVideo();
    }
}

gardez à l'esprit que cela peut provoquer de graves fuites si vous ne gérez pas la vue stockée. En outre, vous devez définir des méthodes pour dire quand vos données sont vidéo et une méthode égale correctement définie.

2
Fco P.

Meilleure façon de gérer l'article à ne pas recycler dans la vue de recyclage, cette réponse résoudra votre problème.

Ne pas recycler l'article

0
Ness Tyagi

Essayez d'utiliser ceci pour cette position particulière:

 holder.setIsRecyclable(false);

J'espère que cela peut vous aider.

0
Simranjeet Singh