Ich versuche herauszufinden, wo das Problem beim Aktualisieren RecyclerView
des Adapters liegt.
Nachdem ich eine neue Produktliste erhalten hatte, versuchte ich:
Aktualisieren Sie das
ArrayList
aus dem Fragment, in demrecyclerView
es erstellt wurde, setzen Sie neue Daten auf den Adapter und rufen Sie dann aufadapter.notifyDataSetChanged()
. Es hat nicht funktioniert.Erstellen Sie einen neuen Adapter, wie andere es getan haben, und es hat für sie funktioniert, aber für mich keine Änderung:
recyclerView.setAdapter(new RecyclerViewAdapter(newArrayList))
Erstellen Sie eine Methode, mit
Adapter
der die Daten wie folgt aktualisiert werden:public void updateData(ArrayList<ViewModel> viewModels) { items.clear(); items.addAll(viewModels); notifyDataSetChanged(); }
Dann rufe ich diese Methode auf, wenn ich die Datenliste aktualisieren möchte. Es hat nicht funktioniert.
So überprüfen Sie, ob ich die recyclerView auf irgendeine Weise ändern kann, und ich habe versucht, mindestens ein Element zu entfernen:
public void removeItem(int position) { items.remove(position); notifyItemRemoved(position); }
Alles blieb wie es war.
Hier ist mein Adapter:
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);
}
}
Und ich initiiere RecyclerView
wie folgt:
recyclerView = (RecyclerView) view.findViewById(R.id.recycler);
recyclerView.setLayoutManager(new GridLayoutManager(getActivity(), 5));
adapter = new RecyclerViewAdapter(items);
adapter.setOnItemClickListener(this);
recyclerView.setAdapter(adapter);
Wie aktualisiere ich die Adapterdaten, um neu empfangene Elemente anzuzeigen?
Update: Das Problem war, dass das Layout, in dem gridView angezeigt wurde, wie folgt aussah:
<?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>
Dann habe ich einfach entfernt LinearLayout
und FrameLayout
als übergeordnetes Layout erstellt.
quelle
items.clear(); items.addAll(newItems);
ist ein hässliches Muster. Wenn Sie hier wirklich defensives Kopieren brauchen,items = new ArrayList(newItems);
wäre das weniger hässlich.Antworten:
Ich arbeite mit RecyclerView und sowohl das Entfernen als auch das Aktualisieren funktionieren gut.
1) ENTFERNEN: Es gibt 4 Schritte, um ein Element aus einer RecyclerView zu entfernen
Diese Codezeile funktioniert für mich.
2) AKTUALISIEREN DER DATEN: Das einzige, was ich tun musste, ist
All dies mussten Sie im Actvity / Fragment-Code tun, nicht im RecyclerView Adapter-Code.
quelle
recycler.removeViewAt(position);
(oder besser gesagtrecycler.removeAllViews()
) die entscheidenden.Dies ist eine allgemeine Antwort für zukünftige Besucher. Die verschiedenen Möglichkeiten zum Aktualisieren der Adapterdaten werden erläutert. Der Prozess umfasst jedes Mal zwei Hauptschritte:
Einzelteil einfügen
Fügen Sie "Schwein" am Index hinzu
2
.Fügen Sie mehrere Elemente ein
Fügen Sie drei weitere Tiere am Index ein
2
.Einzelteil entfernen
Entfernen Sie "Schwein" aus der Liste.
Entfernen Sie mehrere Elemente
Entfernen Sie "Kamel" und "Schaf" aus der Liste.
Entfernen Sie alle Gegenstände
Löschen Sie die gesamte Liste.
Ersetzen Sie die alte Liste durch eine neue Liste
Löschen Sie die alte Liste und fügen Sie eine neue hinzu.
Das
adapter
hat einen Verweis aufdata
, daher ist es wichtig, dass ich keindata
neues Objekt festgelegt habe. Stattdessen habe ich die alten Elemente gelöschtdata
und dann die neuen hinzugefügt.Einzelteil aktualisieren
Ändern Sie das Element "Schafe" so, dass "Ich mag Schafe" angezeigt wird.
Verschieben Sie einen einzelnen Gegenstand
Bewegen Sie "Schafe" von Position
3
zu Position1
.Code
Hier ist der Projektcode als Referenz. Den RecyclerView-Adaptercode finden Sie unter dieser Antwort .
MainActivity.java
Anmerkungen
notifyDataSetChanged()
, wird keine Animation ausgeführt. Dies kann auch ein teurer Vorgang sein. Daher wird die Verwendung nicht empfohlen,notifyDataSetChanged()
wenn Sie nur einen einzelnen Artikel oder eine Reihe von Artikeln aktualisieren.Weitere Studie
quelle
Update single item
, hätte ich Schildkröten mögen sollenDas hat bei mir funktioniert:
Nachdem ich einen neuen Adapter erstellt hatte, der die aktualisierte Liste enthält (in meinem Fall war es eine in eine ArrayList konvertierte Datenbank) und diesen als Adapter festgelegt hatte, versuchte ich es
recyclerView.invalidate()
und es funktionierte.quelle
YourAdapter adapter = (YourAdapter) recyclerView.getAdapter(); adapter.yourSetterMethod(newList); adapter.notifyDataSetChanged();
Das heißt" an, es klingt wie das, was das OP zuerst versucht hat (fügen Sie dies einfach als Kommentar hinzu, damit es jemand anderem helfen kann, wie es in meinem Fall funktioniert hat).Sie haben 2 Möglichkeiten, dies zu tun: Aktualisieren Sie die Benutzeroberfläche vom Adapter:
oder aktualisieren Sie es von recyclerView selbst:
quelle
Eine andere Möglichkeit ist die Verwendung von Diffutil . Es wird die ursprüngliche Liste mit der neuen Liste verglichen und die neue Liste als Aktualisierung verwendet, wenn sich etwas ändert.
Grundsätzlich können wir DiffUtil verwenden, um die alten Daten mit neuen Daten zu vergleichen und notifyItemRangeRemoved sowie notifyItemRangeChanged und notifyItemRangeInserted in Ihrem Namen aufrufen zu lassen.
Ein kurzes Beispiel für die Verwendung von diffUtil anstelle von notifyDataSetChanged:
Ich mache die berechneDiff-Arbeit außerhalb des Hauptthreads, falls es sich um eine große Liste handelt.
quelle
getItems()
. Woher wissen Sie, welche Daten aus der ursprünglichen Liste entfernt / hinzugefügt / aktualisiert werden müssen?Aktualisieren Sie die Daten von Listenansicht, Rasteransicht und Recyclingansicht
oder
quelle
Der beste und coolste Weg, neue Daten zu den aktuellen Daten hinzuzufügen, ist
quelle
Ich habe das gleiche Problem auf andere Weise gelöst. Ich habe keine Daten aus dem Hintergrund-Thread, auf die ich warte. Beginnen Sie also mit einer leeren Liste.
Das ist es.
quelle
Diese Methoden sind effizient und gut geeignet, um eine Basis zu verwenden
RecyclerView
.Sie können sie in einer Adapterklasse oder in Ihrem Fragment oder Ihrer Aktivität implementieren. In diesem Fall müssen Sie den Adapter instanziieren, um die Benachrichtigungsmethoden aufzurufen. In meinem Fall implementiere ich es normalerweise im Adapter.
quelle
Ich fand heraus, dass eine wirklich einfache Möglichkeit, RecyclerView neu zu laden, darin besteht, einfach aufzurufen
Dadurch wird zunächst der gesamte Inhalt von RecyclerView entfernt und anschließend mit den aktualisierten Werten erneut hinzugefügt.
quelle
Ich habe die Antwort nach langer Zeit bekommen
quelle
Wenn nichts in den obigen Kommentaren erwähnt wird, funktioniert es für Sie. Es könnte bedeuten, dass das Problem woanders liegt.
Ein Ort, an dem ich die Lösung gefunden habe, war die Art und Weise, wie ich die Liste auf den Adapter gesetzt habe. In meiner Aktivität war die Liste eine Instanzvariable und ich habe sie direkt geändert, wenn sich Daten geändert haben. Da es sich um eine Referenzvariable handelte, war etwas Seltsames los. Also habe ich die Referenzvariable in eine lokale Variable geändert und eine andere Variable verwendet, um Daten zu aktualisieren und dann an
addAll()
die in den obigen Antworten erwähnte Funktion zu übergeben.quelle