Essayer de comprendre quel est le problème avec la mise à jour de l'adaptateur de RecyclerView
.
Après avoir reçu une nouvelle liste de produits, j'ai essayé de:
Mettez à jour le ArrayList
à partir du fragment où est créé recyclerView
, définissez les nouvelles données sur l'adaptateur, puis appelez adapter.notifyDataSetChanged()
; cela n'a pas fonctionné.
Créez un nouvel adaptateur, comme d'autres l'ont fait, et cela a fonctionné pour eux, mais aucun changement pour moi: recyclerView.setAdapter(new RecyclerViewAdapter(newArrayList))
Créez une méthode dans Adapter
qui met à jour les données comme suit:
public void updateData(ArrayList<ViewModel> viewModels) {
items.clear();
items.addAll(viewModels);
notifyDataSetChanged();
}
J'appelle ensuite cette méthode chaque fois que je souhaite mettre à jour la liste de données; cela n'a pas fonctionné.
Pour vérifier si je peux modifier recyclerView de quelque manière que ce soit, et j'ai essayé de supprimer au moins un élément:
public void removeItem(int position) {
items.remove(position);
notifyItemRemoved(position);
}
Tout est resté tel quel.
Voici mon adaptateur:
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> implements View.OnClickListener {
private ArrayList<ViewModel> items;
private OnItemClickListener onItemClickListener;
public RecyclerViewAdapter(ArrayList<ViewModel> items) {
this.items = items;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler, parent, false);
v.setOnClickListener(this);
return new ViewHolder(v);
}
public void updateData(ArrayList<ViewModel> viewModels) {
items.clear();
items.addAll(viewModels);
notifyDataSetChanged();
}
public void addItem(int position, ViewModel viewModel) {
items.add(position, viewModel);
notifyItemInserted(position);
}
public void removeItem(int position) {
items.remove(position);
notifyItemRemoved(position);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ViewModel item = items.get(position);
holder.title.setText(item.getTitle());
Picasso.with(holder.image.getContext()).load(item.getImage()).into(holder.image);
holder.price.setText(item.getPrice());
holder.credit.setText(item.getCredit());
holder.description.setText(item.getDescription());
holder.itemView.setTag(item);
}
@Override
public int getItemCount() {
return items.size();
}
@Override
public void onClick(final View v) {
// Give some time to the ripple to finish the effect
if (onItemClickListener != null) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
onItemClickListener.onItemClick(v, (ViewModel) v.getTag());
}
}, 0);
}
}
protected static class ViewHolder extends RecyclerView.ViewHolder {
public ImageView image;
public TextView price, credit, title, description;
public ViewHolder(View itemView) {
super(itemView);
image = (ImageView) itemView.findViewById(R.id.image);
price = (TextView) itemView.findViewById(R.id.price);
credit = (TextView) itemView.findViewById(R.id.credit);
title = (TextView) itemView.findViewById(R.id.title);
description = (TextView) itemView.findViewById(R.id.description);
}
}
public interface OnItemClickListener {
void onItemClick(View view, ViewModel viewModel);
}
}
Et j'initie RecyclerView
comme suit:
recyclerView = (RecyclerView) view.findViewById(R.id.recycler);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 5));
adapter = new RecyclerViewAdapter(items);
adapter.setOnItemClickListener(this);
recyclerView.setAdapter(adapter);
Alors, comment puis-je mettre à jour les données de l'adaptateur afin d'afficher les éléments récemment reçus?
Mise à jour: le problème était que la mise en page où gridView était ressemblé:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:tag="catalog_fragment"
Android:layout_height="match_parent">
<FrameLayout
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v7.widget.RecyclerView
Android:id="@+id/recycler"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:clipToPadding="false"/>
<ImageButton
Android:id="@+id/fab"
Android:layout_gravity="top|end"
style="@style/FabStyle"/>
</FrameLayout>
</LinearLayout>
Ensuite, je viens de retirer LinearLayout
et de transformer FrameLayout
en tant que modèle parent.
Je travaille avec RecyclerView et la suppression et la mise à jour fonctionnent bien.
1) SUPPRIMER: Il y a 4 étapes pour supprimer un élément d’un RecyclerView
list.remove(position);
recycler.removeViewAt(position);
mAdapter.notifyItemRemoved(position);
mAdapter.notifyItemRangeChanged(position, list.size());
Cette ligne de codes fonctionne pour moi.
2) MISE À JOUR DES DONNÉES: La seule chose que je devais faire est de
mAdapter.notifyDataSetChanged();
Vous avez dû faire tout cela dans le code Actvity/Fragment et non dans le code de l'adaptateur RecyclerView.
Ceci est une réponse générale pour les futurs visiteurs. Les différentes manières de mettre à jour les données de l'adaptateur sont expliquées. Le processus comprend à chaque fois deux étapes principales:
Ajoutez "Cochon" à l'index 2
.
String item = "Pig";
int insertIndex = 2;
data.add(insertIndex, item);
adapter.notifyItemInserted(insertIndex);
Insérez trois autres animaux à l'index 2
.
ArrayList<String> items = new ArrayList<>();
items.add("Pig");
items.add("Chicken");
items.add("Dog");
int insertIndex = 2;
data.addAll(insertIndex, items);
adapter.notifyItemRangeInserted(insertIndex, items.size());
Supprimer "Cochon" de la liste.
int removeIndex = 2;
data.remove(removeIndex);
adapter.notifyItemRemoved(removeIndex);
Supprimez "Chameau" et "Mouton" de la liste.
int startIndex = 2; // inclusive
int endIndex = 4; // exclusive
int count = endIndex - startIndex; // 2 items will be removed
data.subList(startIndex, endIndex).clear();
adapter.notifyItemRangeRemoved(startIndex, count);
Effacer la liste entière.
data.clear();
adapter.notifyDataSetChanged();
Effacez l'ancienne liste puis ajoutez-en une nouvelle.
// clear old list
data.clear();
// add new list
ArrayList<String> newList = new ArrayList<>();
newList.add("Lion");
newList.add("Wolf");
newList.add("Bear");
data.addAll(newList);
// notify adapter
adapter.notifyDataSetChanged();
La adapter
a une référence à data
, il est donc important que je n’ai pas défini data
sur un nouvel objet. Au lieu de cela, j'ai effacé les anciens éléments de data
, puis ajouté les nouveaux.
Modifiez l'élément "Moutons" pour qu'il indique "J'aime les moutons".
String newValue = "I like sheep.";
int updateIndex = 3;
data.set(updateIndex, newValue);
adapter.notifyItemChanged(updateIndex);
Déplacez "Moutons" de la position 3
à la position 1
.
int fromPosition = 3;
int toPosition = 1;
// update data array
String item = data.get(fromPosition);
data.remove(fromPosition);
data.add(toPosition, item);
// notify adapter
adapter.notifyItemMoved(fromPosition, toPosition);
Voici le code du projet pour votre référence. Le code de l’adaptateur RecyclerView est disponible à l’adresse cette réponse .
MainActivity.Java
public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {
List<String> data;
MyRecyclerViewAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// data to populate the RecyclerView with
data = new ArrayList<>();
data.add("Horse");
data.add("Cow");
data.add("Camel");
data.add("Sheep");
data.add("Goat");
// set up the RecyclerView
RecyclerView recyclerView = findViewById(R.id.rvAnimals);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(),
layoutManager.getOrientation());
recyclerView.addItemDecoration(dividerItemDecoration);
adapter = new MyRecyclerViewAdapter(this, data);
adapter.setClickListener(this);
recyclerView.setAdapter(adapter);
}
@Override
public void onItemClick(View view, int position) {
Toast.makeText(this, "You clicked " + adapter.getItem(position) + " on row number " + position, Toast.LENGTH_SHORT).show();
}
public void onButtonClick(View view) {
insertSingleItem();
}
private void insertSingleItem() {
String item = "Pig";
int insertIndex = 2;
data.add(insertIndex, item);
adapter.notifyItemInserted(insertIndex);
}
private void insertMultipleItems() {
ArrayList<String> items = new ArrayList<>();
items.add("Pig");
items.add("Chicken");
items.add("Dog");
int insertIndex = 2;
data.addAll(insertIndex, items);
adapter.notifyItemRangeInserted(insertIndex, items.size());
}
private void removeSingleItem() {
int removeIndex = 2;
data.remove(removeIndex);
adapter.notifyItemRemoved(removeIndex);
}
private void removeMultipleItems() {
int startIndex = 2; // inclusive
int endIndex = 4; // exclusive
int count = endIndex - startIndex; // 2 items will be removed
data.subList(startIndex, endIndex).clear();
adapter.notifyItemRangeRemoved(startIndex, count);
}
private void removeAllItems() {
data.clear();
adapter.notifyDataSetChanged();
}
private void replaceOldListWithNewList() {
// clear old list
data.clear();
// add new list
ArrayList<String> newList = new ArrayList<>();
newList.add("Lion");
newList.add("Wolf");
newList.add("Bear");
data.addAll(newList);
// notify adapter
adapter.notifyDataSetChanged();
}
private void updateSingleItem() {
String newValue = "I like sheep.";
int updateIndex = 3;
data.set(updateIndex, newValue);
adapter.notifyItemChanged(updateIndex);
}
private void moveSingleItem() {
int fromPosition = 3;
int toPosition = 1;
// update data array
String item = data.get(fromPosition);
data.remove(fromPosition);
data.add(toPosition, item);
// notify adapter
adapter.notifyItemMoved(fromPosition, toPosition);
}
}
notifyDataSetChanged()
, aucune animation ne sera exécutée. Cela peut également être une opération coûteuse, il est donc déconseillé d'utiliser notifyDataSetChanged()
si vous ne mettez à jour qu'un seul élément ou une plage d'éléments.C'est ce qui a fonctionné pour moi:
recyclerView.setAdapter(new RecyclerViewAdapter(newList));
recyclerView.invalidate();
Après avoir créé un nouvel adaptateur contenant la liste mise à jour (dans mon cas, il s'agissait d'une base de données convertie en ArrayList) et l'avoir défini en tant qu'adaptateur, j'ai essayé recyclerView.invalidate()
et tout a fonctionné.
vous avez 2 options pour cela: actualiser l'interface utilisateur à partir de l'adaptateur:
mAdapter.notifyDataSetChanged();
ou actualisez-le à partir de recyclerView lui-même:
recyclerView.invalidate();
Une autre option consiste à utiliser diffutil . Il comparera la liste d'origine à la nouvelle liste et utilisera la nouvelle liste comme mise à jour en cas de changement.
Fondamentalement, nous pouvons utiliser DiffUtil pour comparer les anciennes données avec les nouvelles données et le laisser appeler notifyItemRangeRemoved, notifyItemRangeChanged et notifyItemRangeInserted en votre nom.
Un exemple rapide d'utilisation de diffUtil au lieu de notifyDataSetChanged:
DiffResult diffResult = DiffUtil
.calculateDiff(new MyDiffUtilCB(getItems(), items));
//any clear up on memory here and then
diffResult.dispatchUpdatesTo(this);
//and then, if necessary
items.clear()
items.addAll(newItems)
Je fais le calcul calculer en dehors du fil principal au cas où ce serait une grande liste.
Mise à jour des données de listview, gridview et recyclerview
mAdapter.notifyDataSetChanged();
ou
mAdapter.notifyItemRangeChanged(0, itemList.size());
J'ai résolu le même problème d'une manière différente. Je n'ai pas de données que j'attendais du fil d'arrière-plan, alors commencez par une liste emty.
mAdapter = new ModelAdapter(getContext(),new ArrayList<Model>());
// then when i get data
mAdapter.update(response.getModelList());
// and update is in my adapter
public void update(ArrayList<Model> modelList){
adapterModelList.clear();
for (Product model: modelList) {
adapterModelList.add(model);
}
mAdapter.notifyDataSetChanged();
}
C'est ça.
Le moyen le plus efficace d’ajouter de nouvelles données aux données actuelles est
ArrayList<String> newItems = new ArrayList<String>();
newItems = getList();
int oldListItemscount = alcontainerDetails.size();
alcontainerDetails.addAll(newItems);
recyclerview.getAdapter().notifyItemChanged(oldListItemscount+1, al_containerDetails);
Ces méthodes sont efficaces et vous permettent de commencer à utiliser une base RecyclerView
.
private List<YourItem> items;
public void setItems(List<YourItem> newItems)
{
clearItems();
addItems(newItems);
}
public void addItem(YourItem item, int position)
{
if (position > items.size()) return;
items.add(item);
notifyItemInserted(position);
}
public void addMoreItems(List<YourItem> newItems)
{
int position = items.size() + 1;
newItems.addAll(newItems);
notifyItemChanged(position, newItems);
}
public void addItems(List<YourItem> newItems)
{
items.addAll(newItems);
notifyDataSetChanged();
}
public void clearItems()
{
items.clear();
notifyDataSetChanged();
}
public void addLoader()
{
items.add(null);
notifyItemInserted(items.size() - 1);
}
public void removeLoader()
{
items.remove(items.size() - 1);
notifyItemRemoved(items.size());
}
public void removeItem(int position)
{
if (position >= items.size()) return;
items.remove(position);
notifyItemRemoved(position);
}
public void swapItems(int positionA, int positionB)
{
if (positionA > items.size()) return;
if (positionB > items.size()) return;
YourItem firstItem = items.get(positionA);
videoList.set(positionA, items.get(positionB));
videoList.set(positionB, firstItem);
notifyDataSetChanged();
}
Vous pouvez les implémenter dans une classe d'adaptateur ou dans votre fragment ou activité, mais dans ce cas, vous devez instancier l'adaptateur pour appeler les méthodes de notification. Dans mon cas, je l'implémente généralement dans l'adaptateur.
J'ai découvert qu'un moyen très simple de recharger le RecyclerView consiste simplement à appeler
recyclerView.removeAllViews();
Cela supprimera d'abord tout le contenu de RecyclerView, puis l'ajoutera à nouveau avec les valeurs mises à jour.
Si rien de ce qui est mentionné dans les commentaires ci-dessus ne fonctionne pour vous. Cela pourrait signifier que le problème se situe ailleurs.
À un endroit où j'ai trouvé la solution, j'ai créé la liste avec l'adaptateur. Dans mon activité, la liste était une variable d'instance et je la changeais directement lorsque des données étaient modifiées. Comme il s'agissait d'une variable de référence, il se passait quelque chose d'étrange. J'ai donc remplacé la variable de référence par une variable locale et utilisé une autre variable pour mettre à jour les données, puis passer à la fonction addAll()
mentionnée dans les réponses ci-dessus.
j'ai eu la réponse après un long moment
SELECTEDROW.add(dt);
notifyItemInserted(position);
SELECTEDROW.remove(position);
notifyItemRemoved(position);