196 votes

Android, ListView IllegalStateException : « le contenu de la carte a changé mais ListView ne reçoit pas de notification »

Ce que je veux faire: exécuter un thread d'arrière-plan qui calcule ListView contenu et mise à jour ListView partiellement, alors que les résultats sont calculés.

Ce que je sais que je dois éviter: je ne plaisante pas avec ListAdapter contenu de thread d'arrière-plan, de sorte que j'ai hérité de AsyncTask et de publier le résultat (ajouter des entrées à la carte) à partir de onProgressUpdate. Mon Adaptateur utilise un ArrayList d'objets du résultat, toutes les opérations sur ces arraylists sont synchronisés.

Recherche d'autres personnes: il y a de précieuses données ici. J'ai également souffert de presque quotidiennement des accidents pour le groupe de ~500 utilisateurs, et quand j'ai ajouté la liste.setVisibility(DISPARU)/trackList.setVisibility(VISIBLE) de bloc dans onProgressUpdate, les accidents abaissé par un facteur de 10, mais pas disparu. (il a été suggéré dans la réponse )

Ce que j'en ai parfois: veuillez noter, il arrive vraiment rarement (une fois par semaine pour l'un de 3.5 k utilisateurs). Mais je voudrais me débarrasser de ce bug complètement. Voici partielle 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)
[...]

De l'aide? Pas plus nécessaire, voir ci-dessous

RÉPONSE FINALE: Comme il s'est avéré, j'étais appelant notifyDataSetChanged tous les 5 insertions pour éviter le scintillement et de brusques changements dans la liste. Il ne peut pas être fait d'une telle façon, toujours informer de l'adaptateur lorsque la base de modifications de la liste. Ce bug il a disparu depuis longtemps pour moi maintenant.

122voto

Mullins Points 901

J’ai eu le même problème.

J’ai ajout d’éléments à mon `` à l’extérieur de la thread UI.

J’ai les deux et appelé dans l’UI thread et j’ai résolu ceci.

27voto

gian1200 Points 1766

J’ai eu le même problème, mais je l’ai fixé à l’aide de la méthode

de la classe ListView

23voto

Javanator Points 6536

C'est un MultiThreading Question et en Utilisant Correctement Synchronisé Blocs Ceci peut être empêché. Sans mettre plus de choses sur le Thread de l'INTERFACE utilisateur et en provoquant la perte de la réactivité de l'application.

J'ai aussi été confronté au même. Et comme le plus accepté de répondre suggère d'apporter des changements à la carte de données à partir de l'UI Thread peut résoudre le problème. Que va fonctionner, mais est une solution rapide et facile, mais pas le meilleur.

Comme vous pouvez le voir, pour un cas normal. La mise à jour des données de carte de thread d'arrière-plan et de l'appel de notifyDataSetChanged dans le thread de l'INTERFACE utilisateur travaille.

Cette exception illegalStateException se pose lorsqu'un thread d'interface utilisateur est mise à jour de la vue et un autre thread d'arrière-plan change de nouveau les données. De ce moment, les causes de ce problème.

Donc, si vous permettra de synchroniser tout le code qui est en train de changer la carte de données et de prise de notifydatasetchange appel. Ce problème devrait avoir disparu. Passé pour moi et je suis encore la mise à jour des données de thread d'arrière-plan.

Ici est mon cas spécifique de code pour que d'autres se réfèrent.

Mon chargeur sur l'écran principal des charges de l'annuaire de contacts dans mes sources de données en arrière-plan.

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

Cette PhoneBookManager.getPhoneBookContacts lit de contact à partir du répertoire, et les remplit dans le hashmaps. Qui est directement utilisable pour la Liste des Adaptateurs pour attirer liste.

Il y a un bouton sur mon écran. Qui ouvre une activité où ces numéros de téléphone sont répertoriés. Si j'directement setAdapter sur la liste avant que le thread précédent a terminé son travail qui est en passe de naviagtion cas arrive de moins en moins souvent. Il apparaît de l'exception .Qui est le titre de cette question. Alors, je dois faire quelque chose comme cela dans la deuxième activité.

Mon chargeur dans la deuxième activité attend les premier thread complet. Jusqu'à ce qu'il affiche une barre de progression. De vérifier la loadInBackground de deux chargeurs.

Il crée ensuite l'adaptateur et de le livrer à l'activité, où sur le thread d'interface utilisateur-je appeler setAdapter.

Qui a résolu mon problème.

Ce code est un extrait seulement. Vous avez besoin de changer pour compiler bien pour vous.

@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());    
        }
    }

}

Espérons que cette aide

15voto

triad Points 3235

J’ai résolu ce problème en avoir 2 listes. Une liste que j’utilise pour que l’adaptateur, et je fais toutes les données des changements/mises à jour sur l’autre liste. Cela me permet de faire des mises à jour sur une seule liste dans un thread d’arrière-plan, puis mettez à jour la liste « adaptateur » dans le thread principal/UI :

7voto

Qberticus Points 20157

J’ai écrit ce code et s’exécuter dans une 2.1 émulateur image pendant environ 12 heures et n’a pas obtenu la IllegalStateException. Je vais donner le cadre android le bénéfice du doute sur celui-ci et dire que c’est probablement une erreur dans votre code. J’espère que cette aide. Peut-être que vous pouvez l’adapter à votre liste et les données.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X