web-dev-qa-db-fra.com

Ensemble de données de changement RecyclerView

Je souhaite implémenter la fonctionnalité de recherche pour mon RecyclerView. Lorsque le texte a changé, je souhaite modifier les données affichées avec ce widget. Peut-être cette question a-t-elle déjà été posée ou est-elle simple, mais je ne sais pas comment changer les données à afficher ...

Mon RecyclerView est défini comme suit:

     // 1. get a reference to recyclerView
    mRecyclerView = (RecyclerView)findViewById(R.id.recyclerView);

    // 2. set layoutManger
    mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
    // 3. create an adapter
    mAdapter = new ItemsAdapter(itemsData);
    // 4. set adapter
    mRecyclerView.setAdapter(mAdapter);

Et les données que je montre sont quelque chose comme:

   ItemData itemsData[] = { new ItemData("Mary Richards"),
        new ItemData("Tom Brown"),
        new ItemData("Lucy London")          
};

Donc, quand dois-je fournir à l'adaptateur un autre ensemble de données, un autre tableau (avec un élément par exemple), que dois-je faire?

43
Sandra

Si vous avez des identifiants stables dans votre adaptateur, vous pouvez obtenir de très bons résultats (animations) si vous créez un nouveau tableau contenant les éléments filtrés et appelez

recyclerView.swapAdapter(newAdapter, false);

Utiliser swapAdapter indique à RecyclerView qu'il peut réutiliser les détenteurs de vue. (vs dans setAdapter, il doit recycler toutes les vues et recréer car il ne sait pas que le nouvel adaptateur a le même ViewHolder défini avec l'ancien adaptateur).

Une meilleure approche consisterait à rechercher les éléments supprimés et à appeler notifyItemRemoved(index). N'oubliez pas de supprimer réellement l'élément. Cela laissera RecyclerView exécuter des animations prédictives. En supposant que vous ayez un adaptateur qui utilise en interne une ArrayList, la mise en œuvre ressemblerait à ceci:

// adapter code
final List<ItemData> mItems = new ArrayList(); //contains your items
public void filterOut(String filter) {
   final int size = mItems.size();
   for(int i = size - 1; i>= 0; i--) {
       if (mItems.get(i).test(filter) == false) {
           mItems.remove(i);
           notifyItemRemoved(i);
       }
   }
}

Cela fonctionnerait encore mieux si vous pouviez mettre en lot notifyItemRemoved appels et utiliser plutôt notifyItemRangeRemoved. Cela ressemblerait à: (non testé)

public void filterOut(String filter) {
   final int size = mItems.size();
   int batchCount = 0; // continuous # of items that are being removed
   for(int i = size - 1; i>= 0; i--) {
       if (mItems.get(i).test(filter) == false) {
           mItems.remove(i);
           batchCount ++;
       } else if (batchCount != 0) { // dispatch batch
           notifyItemRangeRemoved(i + 1, batchCount);
           batchCount = 0;
       }
   }
   // notify for remaining
   if (batchCount != 0) { // dispatch remaining
       notifyItemRangeRemoved(0, batchCount);
   }
}

Vous devez étendre ce code pour ajouter des éléments précédemment filtrés mais qui doivent maintenant être visibles (par exemple, l'utilisateur supprime la requête de filtre), mais je pense que celui-ci devrait donner une idée de base.

N'oubliez pas que chaque appel d'élément de notification affecte les suivants (c'est pourquoi je parcours la liste de bout en bout pour l'éviter). Traverser depuis la fin aide également les performances de la méthode ArrayList à supprimer (moins d'éléments à déplacer).

Par exemple, si vous parcouriez la liste depuis le début et supprimez les deux premiers éléments. Vous devriez soit appeler

notifyItemRangeRemoved(0, 2); // 2 items starting from index 0

ou si vous les envoyez un par un

notifyItemRemoved(0);
notifyItemRemoved(0);//because after the previous one is removed, this item is at position 0
89
yigit

Voici ma réponse - merci à Ivan Skoric de son site: http://blog.lovelyhq.com/creating-lists-with-recyclerview-in-Android/

J'ai créé une méthode supplémentaire dans ma classe d'adaptateur:

public void updateList(List<Data> data) {
    mData = data;
    notifyDataSetChanged();
}

Ensuite, chaque fois que vos données changent, vous appelez simplement cette méthode en transmettant vos nouvelles données et votre vue doit changer pour refléter cette dernière.

25
Simon

Réinitialisez simplement votre adaptateur:

mAdapter = new ItemsAdapter(newItemsData);

ou si vous avez seulement besoin de supprimer, ajoutez quelques éléments spécifiques plutôt qu'une liste complète:

mAdapter.notifyItemInserted(position);

ou

mAdapter.notifyItemRemoved(position);
3
Chad Bingham

Si vous souhaitez modifier l’adaptateur complet dans la vue Recycler. vous pouvez simplement le définir par recycler.setAdapter(myAdapter); Il supprimera automatiquement l'ancien adaptateur de la vue Recycler et le remplacera par votre nouvel adaptateur.

1
Ebad Ali

Comme ygit a répondu, swapAdapter est intéressant lorsque vous devez modifier tout le contenu.

Mais, dans mon FlexibleAdapter, vous pouvez mettre à jour les éléments avec updateDataSet. Vous pouvez même configurer l'adaptateur pour qu'il appelle notifyDataSetChanged ou qu'il présente des animations de synchronisation (activé par défaut). Cela, car notifyDataSetChanged tue toutes les animations, mais il est bon d’avoir des listes volumineuses.

Veuillez consulter la description, les pages démoApp et Wiki: https://github.com/davideas/FlexibleAdapter

0
Davideas