web-dev-qa-db-fra.com

RecyclerView: comment effacer les vues en cache/recyclées?

J'utilise un RecyclerView pour afficher une liste d'éléments avec une présentation de la liste. Je passe d'une présentation de liste à une présentation de grille, affichant uniquement un sous-ensemble de toutes les données en mode de présentation. Ce commutateur utilise un code XML de présentation différent de celui utilisé lorsque la présentation de liste est présentée. 

Tout cela fonctionne bien, sauf que lorsque je fais défiler, des vues de disposition de liste recyclées (mises en cache?) Remplissent la grille, mélangées avec les éléments appropriés de la vue de disposition de grille. En d'autres termes, au lieu d'utiliser mon layout_grid.xml pour la disposition de chaque élément dans RecyclerView, j'obtiens les éléments en utilisant la disposition layout_list.xml, mais dans un format de grille.

Cela me dit que LayoutManager fonctionne correctement, passant d'une liste à une disposition en grille. Cependant, tous les éléments de vue d'élément ne sont pas recréés à l'aide de la disposition grille xml, mais des vues de disposition de liste recyclées sont utilisées.

J'ai essayé RecyclerView.removeAllViews(), RecyclerView.removeAllViewInLayout(), RecyclerView.swapAdapter() (pour forcer le rechargement de l'adaptateur), en vain.

Mettre à jour:

Si je fais défiler deux positions dans la liste et que je passe d’une liste à une autre, les deux premières positions ne passent pas par onCreateViewHolder (), mais directement vers onBindViewHolder () et ne sont donc pas obligées d’utiliser la mise en grille. Au lieu de cela, ces deux premiers éléments de position sont recyclés (je pense) et affichés dans leur format de liste.

21
mraviator

D'accord maintenant je comprend. Vous utilisez les deux mises en page? Il existe une méthode pour renvoyer le type de vue d’un élément list/grid (id/position). Vous devez également implémenter correctement cette méthode pour que l’adaptateur puisse recycler la présentation correcte pour la nouvelle vue. Est-ce que tu comprends ce que je veux dire? :)

5
Mann

Utilisation

recyclerView.getRecycledViewPool().clear();
18
Oleg Kovalyk

J'ai eu le même problème. La solution suggérée par Mann fonctionne bien. Une autre option serait de définir le RecycledViewPool du RecyclerView sur une nouvelle instance. Cela fonctionne pour moi aussi.

recyclerView.setRecycledViewPool(new RecyclerView.RecycledViewPool());

Mais je pense que remplacer la méthode getItemViewType () est la solution la plus propre.

7
goflo

Il semble que la réponse acceptée soit la bonne pour votre cas. Vous devez probablement renvoyer un viewType différent.

Si quelqu'un a besoin de trouver un moyen d'effacer les détenteurs de vues en cache et de se retrouver dans ce fil, voici ce que j'ai trouvé qui a fonctionné.

Vous devez appeler setLayoutManager(null) et setAdapter(null). Si vous voulez conserver votre adaptateur, vous pouvez faire quelque chose comme adapter = getAdapter(); setAdapter(null); setAdapter(adapter);

5
cottonBallPaws

La clé ici était de remplacer getItemViewType(int position) et de le configurer afin que je puisse vérifier quel type de vue (liste ou grille) je traite pour cette position, puis définir le traitement de vue approprié pour cette position dans onbindViewHolder(). Ci-dessous, viewFormat est simplement un entier que je règle en liste ou en grille lorsque l'utilisateur appuie sur le bouton du menu pour modifier le format.

@Override
    public int getItemViewType(int position) {
        if (listData.size() == 0) {
            return EMPTY_VIEW;
        } else if (viewFormat == Constants.LIST_FORMATTED) {
            return Constants.LIST_FORMATTED;
        } else if (viewFormat == Constants.GRID_CONDITION) {
            return Constants.GRID_CONDITION;
        }
        return super.getItemViewType(position);
    }

Un utilisateur qui a posté des commentaires sur mon article d'origine m'a informé de cela, mais malheureusement, ces commentaires ont été supprimés. Je remercie cet utilisateur de m'avoir orienté dans la bonne direction. 

3
mraviator

Recyclerview a la mise en cache des vues ainsi que la piscine des vues recyclées (piscine des détenteurs de vues).

Le cache est constitué de vues (vues contenant des données renseignées). Lorsque LayoutManager indique à Recyclerview que la vue n'est plus visible ni nécessaire, Recyclages vérifie si cette vue est toujours valide pour une position donnée. Si elle est valide, elle est ajoutée au cache. Ainsi, la prochaine fois que LM demandera la vue de cette position, elle sera renvoyée. de cache tel qu'il est.

Alors, quelle est recyclé vues piscine? Lorsque les vues sont supprimées du cache ou ne sont plus des vues valides, les données relatives à ces vues sont effacées et seul l'objet détenteur de la vue est conservé dans le pool. Selon le type d'élément, le pool peut avoir des détenteurs de vues de différents types d'élément.

Maintenant, dans votre cas, vos vues ne sont pas valides pour cette position particulière, car vous souhaitez afficher une vue totalement différente. Votre adaptateur doit donc indiquer à Recyclerview que toutes les vues ne sont pas valides. La seule façon de le faire est d'utiliser notifyDataSetChanged pour tous les éléments. Recyclerview supprimera les vues du cache et les ajoutera au pool de vues de récupérateur. Alors maintenant, lorsque LM demande une vue, la vue recyclée (selon itemType) ou la vue nouvellement créée est renvoyée et l'adaptateur lie les données à ces vues.

0
Virat18

Faites ceci Simple !!

adapter.notifyItemRangeRemoved(0,adapter.getItemCount());

  adapter.notifyItemRangeRemoved(0,adapter.getItemCount());
                   for (int i = 0; i < array.length(); i++) {
                        JSONObject object = array.getJSONObject(i);
                         ////
                        data_List.add(data);
                    }
0
Shahjad S