web-dev-qa-db-de.com

Android, ListView IllegalStateException: "Der Inhalt des Adapters wurde geändert, aber ListView hat keine Benachrichtigung erhalten."

Was ich tun möchte: Führt einen Hintergrundthread aus, der den ListView-Inhalt berechnet und ListView teilweise aktualisiert, während die Ergebnisse berechnet werden.

Was ich weiß, muss ich vermeiden: Ich kann mich nicht mit ListAdapter-Inhalten aus dem Hintergrundthread beschäftigen, also habe ich AsyncTask geerbt und das Ergebnis (Einfügen von Einträgen in den Adapter) von onProgressUpdate veröffentlicht. Mein Adapter verwendet ArrayList von Ergebnisobjekten. Alle Vorgänge in diesen Arraylisten werden synchronisiert.

Forschung anderer Leute: Es gibt sehr wertvolle Daten hier . Ich hatte auch fast tägliche Abstürze für eine Gruppe von ~ 500 Benutzern, und als ich list.setVisibility(GONE)/trackList.setVisibility(VISIBLE) block in onProgressUpdate hinzufügte, wurden Abstürze um einen Faktor 10 gesenkt, aber nicht verschwunden. (es wurde vorgeschlagen in antwort )

Was ich manchmal bekam: Bitte beachten Sie, es passiert wirklich selten (einmal pro Woche für einen Benutzer mit 3,5k). Aber ich möchte diesen Fehler vollständig beseitigen. Hier ist teilweise Stacktrace:

`Java.lang.IllegalStateException:` The content of the adapter has changed but ListView  did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131296334, class Android.widget.ListView) with Adapter(class com.transportoid.Tracks.TrackListAdapter)]
at Android.widget.ListView.layoutChildren(ListView.Java:1432)
at Android.widget.AbsListView.onTouchEvent(AbsListView.Java:2062)
at Android.widget.ListView.onTouchEvent(ListView.Java:3234)
at Android.view.View.dispatchTouchEvent(View.Java:3709)
at Android.view.ViewGroup.dispatchTouchEvent(ViewGroup.Java:852)
at Android.view.ViewGroup.dispatchTouchEvent(ViewGroup.Java:884)
at Android.view.ViewGroup.dispatchTouchEvent(ViewGroup.Java:884)
at Android.view.ViewGroup.dispatchTouchEvent(ViewGroup.Java:884)
[...]

Hilfe? Nicht mehr benötigt, siehe unten

FINAL ANSWER: Wie sich herausstellte, rief ich alle 5 Einfügungen notifyDataSetChanged an, um ein Flackern und plötzliche Listenänderungen zu vermeiden. Dies ist nicht möglich. Benachrichtigen Sie den Adapter immer, wenn sich die Basisliste ändert. Dieser Fehler ist für mich schon lange vorbei.

177
tomash

Ich hatte das gleiche Problem.

Ich habe meiner ArrayList-Elemente außerhalb des UI-Threads hinzugefügt.

Lösung: Ich habe beides adding the items gemacht und notifyDataSetChanged() im UI-Thread aufgerufen.

111
Mullins

Ich hatte das gleiche Problem, aber ich habe es mit der Methode behoben

requestLayout();

aus der Klasse ListView

26
gian1200

Dies ist ein MultiThreading Problem und korrekte Verwendung Synchronized Blocks Dies kann verhindert werden, ohne dass dem UI-Thread zusätzliche Elemente hinzugefügt werden und die Reaktionsfähigkeit der App verloren geht.

Ich sah es auch so. Und da die meist akzeptierte Antwort darauf hinweist, dass durch das Ändern der Adapterdaten von UI Thread das Problem gelöst werden kann. Das wird funktionieren, ist aber eine schnelle und einfache Lösung, aber nicht die beste. 

Wie Sie für einen normalen Fall sehen können. Das Aktualisieren des Datenadapters aus dem Hintergrundthread und das Aufrufen von notifyDataSetChanged in UI-Thread funktioniert.

Diese illegalStateException tritt auf, wenn ein UI-Thread die Ansicht aktualisiert und ein anderer Hintergrund-Thread die Daten erneut ändert. Dieser Moment verursacht dieses Problem.

Wenn Sie also den gesamten Code synchronisieren, der die Adapterdaten ändert und notifydatasetchange aufruft. Dieses Problem sollte weg sein. Wie für mich gegangen und ich aktualisiere immer noch die Daten vom Hintergrund-Thread.

Hier ist mein fallspezifischer Code, auf den andere verweisen können.

Mein Loader auf dem Hauptbildschirm lädt die Telefonbuchkontakte im Hintergrund in meine Datenquellen.

    @Override
    public Void loadInBackground() {
        Log.v(TAG, "Init loadings contacts");
        synchronized (SingleTonProvider.getInstance()) {
            PhoneBookManager.preparePhoneBookContacts(getContext());
        }
    }

Dieser PhoneBookManager.getPhoneBookContacts liest den Kontakt aus dem Telefonbuch und füllt sie in die Hashmaps. Welches ist für Listenadapter direkt verwendbar, um Liste zu zeichnen.

Auf meinem Bildschirm befindet sich eine Schaltfläche. Daraufhin wird eine Aktivität geöffnet, in der diese Telefonnummern aufgeführt sind. Wenn ich direkt über die Liste setAdapter setze, bevor der vorherige Thread seine Arbeit beendet hat, geschieht dies seltener. Es erscheint die Ausnahme .Welche Titel dieser SO - Frage. Also muss ich in der zweiten Aktivität so etwas tun.

Mein Loader in der zweiten Aktivität wartet, bis der erste Thread abgeschlossen ist. Bis es einen Fortschrittsbalken anzeigt. Überprüfen Sie das loadInBackground der beiden Lader.

Dann erstellt er den Adapter und liefert ihn an die Aktivität, bei der ich setAdapter in einem UI-Thread aufrufe.

Das hat mein Problem gelöst.

Dieser Code ist nur ein Ausschnitt. Sie müssen es ändern, um es für Sie gut zu kompilieren.

@Override
public Loader<PhoneBookContactAdapter> onCreateLoader(int arg0, Bundle arg1) {
    return new PhoneBookContactLoader(this);
}

@Override
public void onLoadFinished(Loader<PhoneBookContactAdapter> arg0, PhoneBookContactAdapter arg1) {
    contactList.setAdapter(adapter = arg1);
}

/*
 * AsyncLoader to load phonebook and notify the list once done.
 */
private static class PhoneBookContactLoader extends AsyncTaskLoader<PhoneBookContactAdapter> {

    private PhoneBookContactAdapter adapter;

    public PhoneBookContactLoader(Context context) {
        super(context);
    }

    @Override
    public PhoneBookContactAdapter loadInBackground() {
        synchronized (SingleTonProvider.getInstance()) {
            return adapter = new PhoneBookContactAdapter(getContext());    
        }
    }

}

Hoffe das hilft

20
Javanator

Ich habe das gelöst, indem ich 2 Listen habe. Eine Liste verwende ich nur für den Adapter, und ich mache alle Datenänderungen/Aktualisierungen in der anderen Liste. Dadurch kann ich Aktualisierungen für eine Liste in einem Hintergrund-Thread durchführen und dann die Liste "Adapter" im Haupt-/UI-Thread aktualisieren:

List<> data = new ArrayList<>();
List<> adapterData = new ArrayList();

...
adapter = new Adapter(adapterData);
listView.setAdapter(adapter);

// Whenever data needs to be updated, it can be done in a separate thread
void updateDataAsync()
{
    new Thread(new Runnable()
    {
        @Override
        public void run()
        {
            // Make updates the "data" list.
            ...

            // Update your adapter.
            refreshList();
        }
    }).start();
}

void refreshList()
{
    runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
            adapterData.clear();
            adapterData.addAll(data);
            adapter.notifyDataSetChanged();
            listView.invalidateViews();
        }
    });
}
15
triad

Ich schrieb diesen Code und ließ ihn ~ 12 Stunden lang in einem 2.1-Emulator-Image laufen und erhielt nicht die IllegalStateException. Ich werde dem Android-Framework den Vorteil dieses Zweifels geben und sagen, dass dies höchstwahrscheinlich ein Fehler in Ihrem Code ist. Ich hoffe das hilft. Vielleicht können Sie es an Ihre Liste und Daten anpassen.

public class ListViewStressTest extends ListActivity {
    ArrayAdapter<String> adapter;
    ListView list;
    AsyncTask<Void, String, Void> task;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        this.adapter = new ArrayAdapter<String>(this, Android.R.layout.simple_list_item_1);
        this.list = this.getListView();

        this.list.setAdapter(this.adapter);

        this.task = new AsyncTask<Void, String, Void>() {
            Random r = new Random();
            int[] delete;
            volatile boolean scroll = false;

            @Override
            protected void onProgressUpdate(String... values) {
                if(scroll) {
                    scroll = false;
                    doScroll();
                    return;
                }

                if(values == null) {
                    doDelete();
                    return;
                }

                doUpdate(values);

                if(ListViewStressTest.this.adapter.getCount() > 5000) {
                    ListViewStressTest.this.adapter.clear();
                }
            }

            private void doScroll() {
                if(ListViewStressTest.this.adapter.getCount() == 0) {
                    return;
                }

                int n = r.nextInt(ListViewStressTest.this.adapter.getCount());
                ListViewStressTest.this.list.setSelection(n);
            }

            private void doDelete() {
                int[] d;
                synchronized(this) {
                    d = this.delete;
                }
                if(d == null) {
                    return;
                }
                for(int i = 0 ; i < d.length ; i++) {
                    int index = d[i];
                    if(index >= 0 && index < ListViewStressTest.this.adapter.getCount()) {
                        ListViewStressTest.this.adapter.remove(ListViewStressTest.this.adapter.getItem(index));
                    }
                }
            }

            private void doUpdate(String... values) {
                for(int i = 0 ; i < values.length ; i++) {
                    ListViewStressTest.this.adapter.add(values[i]);
                }
            }

            private void updateList() {
                int number = r.nextInt(30) + 1;
                String[] strings = new String[number];

                for(int i = 0 ; i < number ; i++) {
                    strings[i] = Long.toString(r.nextLong());
                }

                this.publishProgress(strings);
            }

            private void deleteFromList() {
                int number = r.nextInt(20) + 1;
                int[] toDelete = new int[number];

                for(int i = 0 ; i < number ; i++) {
                    int num = ListViewStressTest.this.adapter.getCount();
                    if(num < 2) {
                        break;
                    }
                    toDelete[i] = r.nextInt(num);
                }

                synchronized(this) {
                    this.delete = toDelete;
                }

                this.publishProgress(null);
            }

            private void scrollSomewhere() {
                this.scroll = true;
                this.publishProgress(null);
            }

            @Override
            protected Void doInBackground(Void... params) {
                while(true) {
                    int what = r.nextInt(3);

                    switch(what) {
                        case 0:
                            updateList();
                            break;
                        case 1:
                            deleteFromList();
                            break;
                        case 2:
                            scrollSomewhere();
                            break;
                    }

                    try {
                        Thread.sleep(0);
                    } catch(InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }

        };

        this.task.execute(null);
    }
}
7
Rich Schuler

Vor einigen Tagen traf ich dasselbe Problem und verursachte mehrere tausend Abstürze pro Tag. Etwa 0,1% der Benutzer treffen auf diese Situation. Ich habe setVisibility(GONE/VISIBLE) und requestLayout() ausprobiert, aber die Anzahl der Abstürze nimmt nur wenig ab. 

Und ich habe es endlich gelöst. Nichts mit setVisibility(GONE/VISIBLE). Nichts mit requestLayout().

Schließlich fand ich den Grund, dass ich eine Handler verwendet habe, um notifyDataSetChanged() nach Aktualisierungsdaten aufzurufen, was zu einer Art von Folgendem führen kann: 

  1. Aktualisiert Daten an einem Modellobjekt (ich nenne es eine DataSource)
  2. Der Benutzer berührt die Listenansicht (die checkForTap()/onTouchEvent() aufrufen kann, und ruft schließlich layoutChildren() auf.)
  3. Der Adapter ruft Daten vom Modellobjekt ab und ruft notifyDataSetChanged() auf und aktualisiert Ansichten

Und ich habe einen weiteren Fehler gemacht, dass ich in getCount(), getItem() und getView() Felder in DataSource direkt verwende, anstatt sie in den Adapter zu kopieren. So stürzt es schließlich ab, wenn:

  1. Adapter aktualisiert Daten, die die letzte Antwort ergeben
  2. Bei der nächsten Antwort aktualisiert DataSource die Daten, wodurch sich die Anzahl der Elemente ändert
  3. Der Benutzer berührt die Listenansicht. Dies kann ein Tippen oder Verschieben oder Umdrehen sein
  4. getCount() und getView() werden aufgerufen, und listview findet, dass Daten nicht konsistent sind, und wirft Ausnahmen wie Java.lang.IllegalStateException: The content of the adapter has changed but... aus. Eine weitere häufige Ausnahme ist eine IndexOutOfBoundException, wenn Sie die Kopf-/Fußzeile in ListView verwenden.

Die Lösung ist also einfach: Ich kopiere einfach Daten aus meiner DataSource in den Adapter, wenn mein Handler den Adapter zum Abrufen von Daten auslöst und notifyDataSetChanged() aufruft. Der Absturz kommt jetzt nie wieder vor.

3
HJWAJ

Mein Problem betraf die Verwendung eines Filters zusammen mit der ListView.

Beim Festlegen oder Aktualisieren des zugrunde liegenden Datenmodells der ListView habe ich Folgendes getan:

public void updateUnderlyingContacts(List<Contact> newContacts, String filter)
{
    this.allContacts = newContacts;
    this.filteredContacts = newContacts;
    getFilter().filter(filter);
}

Ein Aufruf von filter() in der letzten Zeile bewirkt (und muss), dass notifyDataSetChanged() in der publishResults()-Methode des Filters aufgerufen wird. Dies funktioniert manchmal in Ordnung, besonders in meinem schnellen Nexus 5. In Wirklichkeit verbirgt sich jedoch ein Fehler, den Sie bei langsameren Geräten oder unter ressourcenintensiven Bedingungen bemerken.

Das Problem ist, dass die Filterung asynchron erfolgt. Zwischen dem Ende der filter()-Anweisung und dem Aufruf von publishResults() (beide im UI-Thread) kann ein anderer UI-Thread-Code ausgeführt werden, um den Inhalt des Adapters zu ändern.

Die eigentliche Korrektur ist einfach. Rufen Sie einfach notifyDataSetChanged() auf, bevor Sie die Filterung anfordern:

public void updateUnderlyingContacts(List<Contact> newContacts, String filter)
{
    this.allContacts = newContacts;
    this.filteredContacts = newContacts;
    notifyDataSetChanged(); // Fix
    getFilter().filter(filter);
}
3
cprcrack

Ich habe eine Liste von Feed-Objekten . Sie wird von keinem UI-Thread ..__ angehängt und abgeschnitten. Sie funktioniert problemlos mit dem folgenden Adapter . Ich benutze FeedAdapter.notifyDataSetChanged im UI-Thread, aber wenig später ..__ tun Sie dies so, da meine Feed-Objekte auch dann im lokalen Dienst gespeichert werden, wenn die Benutzeroberfläche deaktiviert ist.

public class FeedAdapter extends BaseAdapter {
    private int size = 0;
    private final List<Feed> objects;

    public FeedAdapter(Activity context, List<Feed> objects) {
        this.context = context;
        this.objects = objects;
        size = objects.size();
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        ...
    }

    @Override
    public void notifyDataSetChanged() {
        size = objects.size();

        super.notifyDataSetChanged();
    }

    @Override
    public int getCount() {
        return size;
    }

    @Override
    public Object getItem(int position) {
        try {
            return objects.get(position);
        } catch (Error e) {
            return Feed.emptyFeed;
        }
    }

    @Override
    public long getItemId(int position) {
        return position;
    }
}
3
ilya

Wäre dies zeitweilig der Fall, stellte sich heraus, dass dieses Problem nur aufgetreten war, als die Liste gescrollt wurde, nachdem ein "weiter laden" -Klick auf das letzte Element geklickt wurde. Wenn die Liste nicht gescrollt wurde, hat alles gut funktioniert.

Nach viel Debugging war es ein Fehler von meiner Seite, aber auch eine Inkonsistenz im Android-Code.

Wenn die Überprüfung erfolgt, wird dieser Code in ListView ausgeführt

        } else if (mItemCount != mAdapter.getCount()) {
            throw new IllegalStateException("The content of the adapter has changed but "
                    + "ListView did not receive a notification. Make sure the content of "

Wenn jedoch onChange auftritt, wird dieser Code in AdapterView (übergeordnetes Element von ListView) ausgelöst.

    @Override
    public void onChanged() {
        mDataChanged = true;
        mOldItemCount = mItemCount;
        mItemCount = getAdapter().getCount();

Beachten Sie, dass der Adapter NICHT garantiert gleich ist!

In meinem Fall habe ich, da es sich um einen 'LoadMoreAdapter' handelte, den WrappedAdapter im getAdapter-Aufruf (für den Zugriff auf die zugrunde liegenden Objekte) zurückgegeben. Dies führte dazu, dass die Zählungen aufgrund des zusätzlichen Elements "Mehr laden" und der geworfenen Ausnahme unterschiedlich waren.

Ich habe das nur gemacht, weil die Dokumente es so erscheinen lassen, als sei es in Ordnung

ListView.getAdapter Javadoc

Gibt den aktuell in dieser ListView verwendeten Adapter zurück. Das zurückgegebene Adapter ist möglicherweise nicht derselbe Adapter, der an .__ übergeben wird. setAdapter (ListAdapter), kann jedoch ein WrapperListAdapter sein.

3
aaronvargas

Dies ist ein bekannter Fehler in Android 4 bis 4.4 (KitKat) und wurde in "> 4.4" behoben. 

Siehe hier: https://code.google.com/p/Android/issues/detail?id=71936

2

Selbst wenn ich in meiner XMPP-Benachrichtigungsanwendung das gleiche Problem hatte, muss die Empfängernachricht wieder zur Listenansicht hinzugefügt werden (mit ArrayList implementiert). Wenn ich versuchte, den Empfängerinhalt über MessageListener (separater Thread) hinzuzufügen, wird die Anwendung mit dem obigen Fehler beendet. Ich habe das Problem gelöst, indem ich den Inhalt meiner arraylist & setListviewadapater über die runOnUiThread-Methode hinzugefügt habe, die Teil der Activity-Klasse ist. Das hat mein Problem gelöst.

2
Balaji

Ich hatte das gleiche Problem mit genau dem gleichen Fehlerprotokoll ... In meinem Fall fügt onProgress() der AsyncTask die Werte mithilfe von mAdapter.add(newEntry) zum Adapter hinzu. Um zu verhindern, dass die Benutzeroberfläche weniger ansprechbar ist, setze ich mAdapter.setNotifyOnChange(false) und rufe mAdapter.notifyDataSetChanged() 4 mal die Sekunde auf. Einmal pro Sekunde wird das Array sortiert.

Dies funktioniert gut und sieht sehr süchtig aus, aber leider ist es möglich, es durch häufiges Berühren der angezeigten Listenelemente zum Absturz zu bringen.

Es scheint jedoch, dass ich eine akzeptable Problemumgehung gefunden habe..__ Meine Vermutung, dass der Adapter selbst wenn Sie nur an dem UI-Thread arbeiten, nicht viele Änderungen an den Daten akzeptiert, ohne notifyDataSetChanged() aufzurufen eine Warteschlange erstellt, in der alle neuen Elemente gespeichert werden, bis die genannten 300 ms abgelaufen sind. Wenn dieser Moment erreicht ist, füge ich alle gespeicherten Elemente auf einmal hinzu und rufe notifyDataSetChanged(). Bisher war ich konnte die Liste nicht mehr abstürzen.

2
Lars K.

Ich war mit einem ähnlichen Problem konfrontiert, wie ich es in meinem Fall gelöst habe. Ich überprüfe, ob task bereits RUNNING oder FINISHED ist, da eine Task nur einmal ausgeführt werden kann. Nachfolgend sehen Sie einen partiellen und angepassten Code aus meiner Lösung.

public class MyActivity... {
    private MyTask task;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       // your code
       task = new MyTask();
       setList();
    }

    private void setList() {
    if (task != null)
        if (task.getStatus().equals(AsyncTask.Status.RUNNING)){
            task.cancel(true);
            task = new MyTask();
            task.execute();         
        } else if (task.getStatus().equals(AsyncTask.Status.FINISHED)) {
            task = new MyTask();
            task.execute();
        } else 
            task.execute();
    }

    class MyTask extends AsyncTask<Void, Item, Void>{
       List<Item> Itens;

       @Override
       protected void onPreExecute() {

        //your code

        list.setVisibility(View.GONE);
        adapterItem= new MyListAdapter(MyActivity.this, R.layout.item, new ArrayList<Item>());
        list.setAdapter(adapterItem);

        adapterItem.notifyDataSetChanged();
    }

    @Override
    protected Void doInBackground(Void... params) {

        Itens = getItens();
        for (Item item : Itens) {
            publishProgress(item );
        }

        return null;
    }

    @Override
    protected void onProgressUpdate(Item ... item ) {           
        adapterItem.add(item[0]);
    }

    @Override
    protected void onPostExecute(Void result) {
        //your code
        adapterItem.notifyDataSetChanged();     
        list.setVisibility(View.VISIBLE);
    }

}

}
1
Leonardo Costa

In meinem Fall habe ich die Methode GetFilter() auf einem Adapter von der TextWatcher() Methode auf main Activity aufgerufen und die Daten mit einer For-Schleife an GetFilter()..__ hinzugefügt. Die Lösung war geändert die For-Schleife an AfterTextChanged() als Untermethode für Hauptaktivität und löschen Sie den Aufruf an GetFilter()

1
sek13300

Eine Ursache für diesen Absturz ist, dass das ArrayList-Objekt nicht vollständig geändert werden kann ..__ Wenn ich ein Element entferne, muss ich Folgendes tun:

mList.clear();
mList.addAll(newDataList);

Dies hat den Absturz für mich behoben.

1
andude

Ich hatte das gleiche Problem und habe es gelöst. Mein Problem war, dass ich eine listview, einen Array-Adapter und einen Filter verwendete. Bei der Methode performFiltering habe ich mich mit dem Array beschäftigt, das die Daten enthält, und dies war das Problem, da diese Methode nicht im UI-Thread ausgeführt wird und EVENTUALLY einige Probleme verursacht.

1
Gusthema

Bitte versuchen Sie eine dieser Lösungen:

  1. Wenn Sie der Datenliste in einem Thread (oder der doInBackground-Methode) ein neues Objekt hinzufügen, tritt dieser Fehler manchmal auf. Die Lösung ist: Erstellen Sie eine temporäre Liste und fügen Sie dieser Liste Daten in Thread hinzu (oder doInBackground). Kopieren Sie dann alle Daten aus der temporären Liste in die Liste des Adapters im UI-Thread (oder onPostExcute)

  2. Stellen Sie sicher, dass alle UI-Aktualisierungen im UI-Thread aufgerufen werden.

0
Phuc Tran

Ich hatte die gleiche Bewertung, ich hatte viele Buttongroups innerhalb meines Elements in der Listenansicht und ich habe einige boolesche Werte in meinem Element geändert, z.

mein Problem trat auf, weil ich eine Methode in getView () aufgerufen habe; und speicherte ein Objekt in sharepreference, also hatte ich den gleichen Fehler oben

Wie ich es gelöst habe; Ich habe meine Methode in getView () entfernt, um notifyDataSetInvalidated () und das Problem zu beheben

   @Override
    public void notifyDataSetChanged() {
        saveCurrentTalebeOnShare(currentTalebe);
        super.notifyDataSetChanged();
    }
0
Sam

ich hatte das gleiche Problem. endlich habe ich die lösung

schließen Sie vor dem Aktualisieren der Listenansicht die Softkey-Tastatur zuerst. danach set Datenquelle und rufen Sie notifydatasetchanged () auf.

beim internen Schließen des Tastenfelds aktualisiert listview seine Benutzeroberfläche. Es ruft so lange an, bis die Tastatur geschlossen wird. Bei einer Änderung der Datenquelle wird diese Ausnahme ausgelöst. Wenn Daten in onActivityResult aktualisiert werden, besteht die Möglichkeit, dass derselbe Fehler auftritt.

 InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);

        view.postDelayed(new Runnable() {
            @Override
            public void run() {
                refreshList();
            }
        },100L);
0
sreejith

Wie @ Mullins sagte "
Ich habe sowohl die Elemente hinzugefügt als auch notifyDataSetChanged() im UI-Thread aufgerufen und dies gelöst. - Mullins ".

In meinem Fall habe ich asynctask und ich habe notifyDataSetChanged() in der doInBackground()-Methode aufgerufen und das Problem ist gelöst, als ich von onPostExecute() anrief, erhielt ich die Ausnahme.

0
Ciro Mine

Meine Lösung:

1) Erstellen Sie einen temp ArrayList.

2) Führen Sie Ihre schweren Arbeiten (sqlite-Zeilenabruf, ...) in der doInBackground-Methode aus und fügen Sie der temporären Arrayliste Elemente hinzu.

3) Fügen Sie alle Elemente aus der temporären Liste der Arrayliste Ihrer Liste in der onPostExecute-Methode hinzu.

note: Sie möchten möglicherweise einige Elemente aus der Listenansicht und aus der SQLite-Datenbank löschen und möglicherweise einige Dateien löschen, die sich auf Elemente aus der SD-Karte beziehen. Entfernen Sie einfach Elemente aus der Datenbank, entfernen Sie die zugehörigen Dateien und fügen Sie sie in temporäre Arrayliste in background thread ein. dann löschen Sie in UI thread in der temporären Arrayliste vorhandene Elemente aus der Arrayliste der Listview.

Hoffe das hilft.

0
Nobody8

Ich hatte eine benutzerdefinierte ListAdapter und rief am Anfang und nicht am Ende der Methode super.notifyDataSetChanged() auf

@Override
public void notifyDataSetChanged() {
    recalculate();
    super.notifyDataSetChanged();
}
0
Pascalius

ich habe dasselbe Problem, wenn Sie neue Daten in Lazy Image Loader hinzufügen Ich habe gerade gestellt 

         adapter.notifyDataSetChanged();

im 

       protected void onPostExecute(Void args) {
        adapter.notifyDataSetChanged();
        // Close the progressdialog
        mProgressDialog.dismiss();
         }

hoffe es hilft dir

0
Hobii Sgonf

Ich habe auch genau den gleichen Fehler erhalten und AsyncTask verwendet:

`Java.lang.IllegalStateException:` The content of the adapter has changed but ListView  did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. [in ListView(2131296334, class Android.widget.ListView) with Adapter... etc

Ich habe es gelöst, indem ichadapter.notifyDataSetChanged(); am unteren Ende meines UI-Threads abgelegt habe. Dies ist meine AsyncTask-Methode onPostExecute. So was :

 protected void onPostExecute(Void aVoid) {

 all my other stuff etc...
    all my other stuff etc...

           adapter.notifyDataSetChanged();

                }

            });
        }

Jetzt funktioniert meine App.

EDIT: Tatsächlich stürzte meine App immer noch etwa alle 1 von 10 Mal ab und gab den gleichen Fehler ab.

Irgendwann bin ich in einem früheren Beitrag auf runOnUiThread gestoßen, was ich für nützlich hielt. Also habe ich es in meine doInBackground-Methode eingefügt:

@Override
protected Void doInBackground(Void... voids) {

    runOnUiThread(new Runnable() {
                      public void run() { etc... etc...

Und ich habe die adapter.notifyDataSetChanged();-Methode entfernt. Nun stürzt meine App nie ab. 

0
CHarris