Ich habe eine, ListView
die Nachrichten anzeigt. Sie enthalten ein Bild, einen Titel und Text. Das Bild wird in einen separaten Thread geladen (mit einer Warteschlange und allen) und wenn das Bild heruntergeladen wird, rufe ich jetzt notifyDataSetChanged()
den Listenadapter auf, um das Bild zu aktualisieren. Dies funktioniert, aber getView()
wird immer zu häufig genannt, da notifyDataSetChanged()
Anrufe getView()
für alle sichtbaren Elemente. Ich möchte nur das einzelne Element in der Liste aktualisieren. Wie würde ich das machen?
Probleme, die ich mit meinem aktuellen Ansatz habe, sind:
- Das Scrollen ist langsam
- Ich habe eine Einblendanimation auf dem Bild, die jedes Mal auftritt, wenn ein einzelnes neues Bild in der Liste geladen wird.
Diese Frage wurde bei Google I / O 2010 gestellt. Sie können sie hier ansehen:
Die Welt von ListView, Zeit 52:30
Im Grunde , was Romain Guy erklärt ist zu nennen
getChildAt(int)
auf dieListView
die Ansicht zu erhalten und (glaube ich) AufrufgetFirstVisiblePosition()
die Korrelation zwischen Position und Index , um herauszufinden.Romain verweist auch auf das Projekt namens Shelves als Beispiel. Ich denke, er meint die Methode
ShelvesActivity.updateBookCovers()
, aber ich kann den Aufruf von nicht findengetFirstVisiblePosition()
.FANTASTISCHE UPDATES KOMMEN:
Das RecyclerView wird dies in naher Zukunft beheben. Wie unter http://www.grokkingandroid.com/first-glance-androids-recyclerview/ ausgeführt , können Sie Methoden aufrufen, um die Änderung genau anzugeben, z.
Außerdem wird jeder möchte die neuen Ansichten basierend auf RecyclerView verwenden , da sie mit gut aussehenden Animationen belohnt werden! Die Zukunft sieht großartig aus! :-)
quelle
So habe ich es gemacht:
Ihre Elemente (Zeilen) müssen eindeutige IDs haben, damit Sie sie später aktualisieren können. Legen Sie das Tag jeder Ansicht fest, wenn die Liste die Ansicht vom Adapter erhält. (Sie können auch ein Schlüssel-Tag verwenden, wenn das Standard-Tag an einer anderen Stelle verwendet wird.)
Überprüfen Sie für das Update jedes Element der Liste. Wenn eine Ansicht mit der angegebenen ID vorhanden ist, ist sie sichtbar, sodass wir das Update durchführen.
Es ist tatsächlich einfacher als andere Methoden und besser, wenn Sie mit IDs und nicht mit Positionen umgehen! Außerdem müssen Sie update für Elemente aufrufen, die sichtbar werden.
quelle
Holen Sie sich die Modellklasse zuerst als global wie dieses Modellklassenobjekt
und initialisiere es auf global
Rufen Sie die aktuelle Zeile der Ansicht vom Modell ab, indem Sie sie als globales Modell initialisieren
Setzen Sie den geänderten Wert auf die zu setzende globale Modellobjektmethode und fügen Sie den notifyDataSetChanged hinzu, der für mich funktioniert
Hier ist eine verwandte Frage dazu mit guten Antworten.
quelle
Die Antworten sind klar und richtig, ich werde hier eine Idee für den
CursorAdapter
Fall hinzufügen .Wenn Sie eine Unterklasse
CursorAdapter
(oderResourceCursorAdapter
, oderSimpleCursorAdapter
) haben, können Sie entweder Methoden implementierenViewBinder
oder überschreiben,bindView()
undnewView()
diese erhalten keinen aktuellen Listenelementindex in Argumenten. Wenn einige Daten eintreffen und Sie relevante sichtbare Listenelemente aktualisieren möchten, woher kennen Sie deren Indizes?Meine Problemumgehung war:
newView()
notifyDatasetChanged()
alle zu aktualisieren und zu aktualisierenAufgrund des Ansichtsrecyclings entspricht die Anzahl der Ansichtsreferenzen, die ich speichern und iterieren muss, ungefähr der Anzahl der auf dem Bildschirm sichtbaren Listenelemente.
quelle
Für RecycleView verwenden Sie bitte diesen Code
quelle
Ich habe den Code verwendet, der Erik bereitgestellt hat, funktioniert hervorragend, aber ich habe einen komplexen benutzerdefinierten Adapter für meine Listenansicht und wurde mit der zweimaligen Implementierung des Codes konfrontiert, der die Benutzeroberfläche aktualisiert. Ich habe versucht, die neue Ansicht von der getView-Methode meines Adapters abzurufen (die Arrayliste mit den Listenansichtsdaten wurde bereits aktualisiert / geändert):
Es funktioniert gut, aber ich weiß nicht, ob dies eine gute Praxis ist. Ich muss also nicht den Code implementieren, der das Listenelement zweimal aktualisiert.
quelle
genau das habe ich benutzt
quelle
Ich habe eine andere Lösung wie die RecyclyerView- Methode void entwickelt
notifyItemChanged(int position)
und die CustomBaseAdapter- Klasse wie folgt erstellt :Vergessen Sie nicht, auch eine CustomDataSetObservable-Klasse für eine
mDataSetObservable
Variable in CustomAdapterClass zu erstellen :In der Klasse CustomBaseAdapter gibt es eine Methode
notifyItemChanged(int position)
, und Sie können diese Methode aufrufen, wenn Sie eine Zeile aktualisieren möchten, wo immer Sie möchten (vom Klicken auf die Schaltfläche oder an einer beliebigen Stelle, an der Sie diese Methode aufrufen möchten). Und voila!, Ihre einzelne Zeile wird sofort aktualisiert.quelle
Meine Lösung: Wenn es korrekt ist *, aktualisieren Sie die Daten und sichtbaren Elemente, ohne die gesamte Liste neu zu zeichnen. Andernfalls notifyDataSetChanged.
Richtig - oldData size == neue Datengröße und alte Daten-IDs und deren Reihenfolge == neue Daten-IDs und Reihenfolge
Wie:
und natürlich:
Ignorieren Sie den letzten Parameter für bindView (ich verwende ihn, um festzustellen, ob ich Bitmaps für ImageDrawable recyceln muss oder nicht).
Wie oben erwähnt, entspricht die Gesamtzahl der "sichtbaren" Ansichten ungefähr der Menge, die auf den Bildschirm passt (ohne Berücksichtigung von Orientierungsänderungen usw.).
quelle
Zusätzlich zu dieser Lösung ( https://stackoverflow.com/a/3727813/5218712 ) möchten Sie nur hinzufügen, dass sie nur funktionieren sollte, wenn
listView.getChildCount() == yourDataList.size();
in ListView eine zusätzliche Ansicht vorhanden sein könnte.Beispiel für das Auffüllen der untergeordneten Elemente:
quelle