Beispiel notifyDataSetChanged


166

Ich versuche in meinem zu verwenden Android Application das notifyDataSetChanged()für ein Verfahren , ArrayAdapteraber es für mich nicht funktioniert.

ich fand als Antwort , dass notifyDataSetChanged()das im Haupt-Thread laufen sollte, aber es gab kein Beispiel dafür.

Könnte jemand ein Beispiel oder zumindest einen Link senden?!



Sie können diesen Blog und dieses Beispiel in Github und dies auch
Cabezas

Antworten:


328

Für einen umfassenden ArrayAdapter, notifyDataSetChangedfunktioniert nur , wenn Sie die verwenden add(), insert(), remove(), und clear()auf dem Adapter.

Wenn ein erstellt ArrayAdapterwird, enthält es die Referenz für das übergebene ListElement. Wenn Sie Listein Mitglied übergeben, das Mitglied einer Aktivität war, und dieses Aktivitätsmitglied später ändern, enthält das ArrayAdapternoch einen Verweis auf das Original List. Der Adapter weiß nicht, dass Sie das Listin der Aktivität geändert haben .

Sie haben folgende Möglichkeiten:

  1. Verwenden Sie die Funktionen des ArrayAdapterauf die zugrunde liegende Liste zu ändern ( add(), insert(), remove(), clear(), etc.)
  2. Erstellen Sie die ArrayAdaptermit den neuen ListDaten neu. (Verbraucht viele Ressourcen und Speicherbereinigung.)
  3. Erstellen Sie eine eigene Klasse, die von abgeleitet ist BaseAdapterund die ListAdapterdas Ändern der zugrunde liegenden ListDatenstruktur ermöglicht.
  4. Verwenden Sie diese Option notifyDataSetChanged()jedes Mal, wenn die Liste aktualisiert wird. Verwenden Sie das runOnUiThread()of , um es im UI-Thread aufzurufen Activity. Dann notifyDataSetChanged()wird es funktionieren.

13
Achten Sie auch darauf, Ihren Daten 'neue' Objekte zuzuweisen. Verwenden Sie stattdessen clear (), füllen Sie die Daten neu / nehmen Sie Änderungen an den Daten vor und rufen Sie dann notifyDataSetChanged ()
moonlightcheese am

Aber was ist, wenn wir so anrufen notifyDataSetChanged(): ((BaseAdapter) arrayAdapter).notifyDataSetChanged();?
TeoREtik

2
Ich verwende BaseExpandableListAdapter, es hat keine Funktionen zum Hinzufügen () oder Entfernen (), daher speichere ich meine Map als Mitgliedsvariable. Ich aktualisiere Map und rufe notifyDatasetChanged () auf, aber es passiert nichts. Wenn ich die Wahl # 4 benutze, funktioniert es. Warum???
Smaragdhieu

Ich verwende ArrayAdapter für benutzerdefiniertes GridView. Ich füge Bilder hinzu, wenn ich sie aus URLs erhalte, indem ich adapter.add (dataReceived) aufrufe. Dies funktioniert gut, fügt Daten hinzu, aber warum es aktualisiert wird und nach oben geht. Ich möchte Elemente anzeigen, die ohne Aktualisierung der Liste hinzugefügt werden. (Was Sie tun möchten, ist mit Android GridView mit notifyDatasetChanged () zu arbeiten.) Wie kann ich es in diesem customGridView (StaggeredGridView) funktionieren lassen.
MobileEvangelist

1
Ich habe versucht, meinen eigenen BaseAdapter zu erstellen, um der Liste Sortiermethoden hinzuzufügen, aber aus irgendeinem Grund würde es einfach nicht funktionieren. Nicht dass meine App langsam ist, selbst wenn ich den gesamten Adapter mit einer sortierten Arrayliste neu erstelle, aber es ärgert mich trotzdem. Wie genau würde es aber viel Müll verursachen? Ich gehe davon aus, dass das tatsächliche Array kostspieliger Daten als Referenz in der Aktivität zum Aufrufen des Adapters aufbewahrt wird, was bedeutet, dass nur der Adapter erfasst wird.
G_V

34

Sie können die runOnUiThread()Methode wie folgt verwenden. Wenn Sie a nicht verwenden ListActivity, passen Sie einfach den Code an, um einen Verweis auf Ihren zu erhalten ArrayAdapter.

final ArrayAdapter adapter = ((ArrayAdapter)getListAdapter());
runOnUiThread(new Runnable() {
    public void run() {
        adapter.notifyDataSetChanged();
    }
});

1
Ich habe versucht, das Codefragment von Ihnen in meinem Code (Sie finden es hier stackoverflow.com/questions/3667442/how-to-refresh-adapter ) in der onCreate-Methode hinzuzufügen, aber ich habe immer noch keinen Erfolg :( Vielleicht war es falsch, es hinzuzufügen?!
Tima

1
In Ihrer Frage wurde nur gefragt, wie Sie die Methode aufrufen und im Haupt-UI-Thread ausführen können. Dies beantwortet diese Frage. In Ihrem speziellen Fall ( stackoverflow.com/questions/3670500/… ) sollten Sie AsyncTask und seine onPostExecute () -Methode in Betracht ziehen.
Brian

12

Ich habe kürzlich zu diesem Thema geschrieben, obwohl dieser Beitrag alt ist, dachte ich, dass er für jemanden hilfreich sein wird, der wissen möchte, wie man BaseAdapter.notifyDataSetChanged()Schritt für Schritt und auf korrekte Weise implementiert .

Befolgen Sie die Anweisungen zum korrekten Implementieren von BaseAdapter.notifyDataSetChanged () in Android oder dem neueren Blog BaseAdapter.notifyDataSetChanged () .


Hallo, ich habe das erste Link-Beispiel ausprobiert, aber stattdessen habe mItem.add()ich nur ein Element bearbeitet, was bedeutet mItem.get(position).setImage(encodedImage), dass es möglicherweise einen Fehler gibt. NullPointer-Ausnahme nur für add (), clear (), remove () usw.
Shreekant N

notifyDataSetChanged funktioniert zum Bearbeiten oder Ändern von Datensätzen. Ihr Nullzeiger ist wegen etwas anderem. Überprüfen Sie die Protokolle.
Arif Nadeem

7

Ich hatte das gleiche Problem und ziehe es vor, nicht den gesamten ArrayAdapter kontinuierlich durch eine neue Instanz zu ersetzen. So lasse ich den AdapterHelper das schwere Heben woanders machen.

Fügen Sie dies dort hinzu, wo Sie normalerweise benachrichtigen würden (versuchen)

new AdapterHelper().update((ArrayAdapter)adapter, new ArrayList<Object>(yourArrayList));
adapter.notifyDataSetChanged();

AdapterHelper-Klasse

public class AdapterHelper {
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void update(ArrayAdapter arrayAdapter, ArrayList<Object> listOfObject){
        arrayAdapter.clear();
        for (Object object : listOfObject){
            arrayAdapter.add(object);
        }
    }
}

Ich habe ein paar andere ArrayAdapter in meinem Code und sie haben ohne Probleme funktioniert. Heute Abend habe ich beschlossen, einen SimpleCursorAdapter in einen ArrayAdapter zu verwandeln, und es würde nicht funktionieren. Nachdem ich ein paar Stunden damit zu kämpfen hatte und versucht hatte, einen Grund zu finden, warum es nicht funktionieren würde, fand ich Ihre AdapterHelper-Klasse und JETZT FUNKTIONIERT ES! Vielen Dank!
Pridegeekdad

1
Dies kann leicht in einer Funktion durchgeführt werden ... WARUM würden Sie eine neue Klasse dafür instanziieren?
TechiServices

2
In Java werden Funktionen Methoden genannt. Was würden Sie vorschlagen, haben Sie diese hochgradig wiederverwendbare Methode vielleicht in derselben Klasse wie der Array-Adapter? Oder das Fragment / die Aktivität mit der Listenansicht? Also ja, es ist in einer Klasse, in der es wiederverwendet werden kann. Wenn Sie es auf jeden Fall statisch machen möchten, fahren Sie fort.
Kevin Parker

1
Gute Idee. Eine andere Möglichkeit wäre, ArrayAdapter mit dem Namen ArrayAdapterCompat zu erweitern und die Methode addAll (..) zu überschreiben, da diese nur seit API 11 verfügbar ist. Überprüfen Sie dort die API-Ebene und verwenden Sie sie super.addAll(..)für API> 11 und super.add (.. ) in Kombination mit einer Iteration wie Ihrer : if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { super.addAll(items); } else { for (Object o : collection) { super.add(o); } }. Erweitern Sie jetzt einfach Ihre neue Adapterklasse.
Konsumierer

Perfekt! Vielen Dank @Kevin - das war genau das, was ich brauchte!
Kibi

3

Ich weiß, dass dies eine späte Antwort ist, aber ich hatte ein ähnliches Problem und konnte es mithilfe von lösen notifyDataSetChanged() der richtigen Stelle verwendete.

Meine Situation war also wie folgt.

Ich musste eine Listenansicht in einer Aktionsleistenregisterkarte (Fragment) mit Inhalten aktualisieren, die von einer völlig anderen Aktivität zurückgegeben wurden. Die Listenansicht würde jedoch zunächst keine Änderungen widerspiegeln. Wenn ich jedoch auf eine andere Registerkarte klickte und dann zur gewünschten Registerkarte zurückkehrte, wurde die Listenansicht mit dem richtigen Inhalt aus der anderen Aktivität aktualisiert. Um dies zu lösen, habe ich verwendetnotifyDataSetChanged() den Aktionsleistenadapter im Code der Aktivität verwendet, die die Daten zurückgeben musste.

Dies ist das Code-Snippet, das ich in der Aktivität verwendet habe.

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    switch (item.getItemId()) 
    {
        case R.id.action_new_forward:

            FragmentTab2.mListAdapter.notifyDataSetChanged();//this updates the adapter in my action bar tab
            Intent ina = new Intent(getApplicationContext(), MainActivity.class);
            ina.putExtra("stra", values1);
            startActivity(ina);// This is the code to start the parent activity of my action bar tab(fragment).
    }
}

Diese Aktivität würde einige Daten zurückgeben FragmentTab2und meine Listenansicht direkt in aktualisieren FragmentTab2.

Hoffe jemand findet das nützlich!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.