android -Le contenu de la carte a changé, mais ListView n'a pas reçu une notification
J'obtiens cette erreur :
java.lang.IllegalStateException: Le contenu de la carte a changé, mais ListView n'a pas reçu de notification. Assurez-vous que le contenu de votre carte n'est pas modifié à partir d'un thread d'arrière-plan, mais seulement à partir de la thread de l'INTERFACE utilisateur. [ListView(2131034188, la classe android.widget de.ListView) avec Adaptateur classe .MainActivity$ListAdapter)]
C'est ce que je fais , je lance un AsyncTask et d'obtenir des données json , puis , onPostExecute, j'appelle ListAdapter qui met les données à la liste .
@Override
protected Void doInBackground(Void... arg0) {
Spots_tab1_json sh = new Spots_tab1_json();
String jsonStr = sh.makeServiceCall(url + page, Spots_tab1_json.GET);
if (jsonStr != null) {
JSONObject jsonObj = new JSONObject(jsonStr);
contacts = jsonObj.getJSONArray(TAG_CONTACTS);
for (int i = 0; i < contacts.length(); i++) {
JSONObject c = contacts.getJSONObject(i);
String onvan = new String(c.getString("onvan").getBytes("ISO-8859-1"), "UTF-8");
String id = new String(c.getString("id").getBytes("ISO-8859-1"), "UTF-8");
String dates = new String(c.getString("dates").getBytes("ISO-8859-1"), "UTF-8");
String price = new String(c.getString("gheymat").getBytes("ISO-8859-1"), "UTF-8");
HashMap<String, String> contact = new HashMap<String, String>();
contact.put("onvan", onvan);
contact.put("img", new String(c.getString("img").getBytes("ISO-8859-1"), "UTF-8"));
contactList.add(contact);
}
}
}
}
@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);
if (!isCancelled() && goterr == false) {
final ListAdapter ladap=new ListAdapter(MainActivity.this, contactList);
lv.setAdapter(ladap);
runOnUiThread(new Runnable() {
public void run() {
ladap.notifyDataSetChanged();
}});
}
}
et après ça, ma listView est construit. Je l'ai testé sur plusieurs appareils différents , non d'entre eux avait aucun problème, mais certains utilisateurs m'a dit et je me suis connecté et de voir cette erreur.
Que dois-je faire pour le résoudre ? quel est le problème ?
vous remercie
runOnUiThread(...)
? vous pouvez normalement appel ladap.notifyDataSetChanged()
onPostExecute(...)
s'exécute sur UI
fil lui-même.Pouvez-vous montrer
doInBackground()
trop? Plus précisément, vous pouvez peut-être modifier contactList
là, qui est sans doute encore lié à la carte. Cela peut d'ailleurs conduire à un état illégales, lorsque la carte est accessible lorsqu'il est/en cours de modification dans le thread d'arrière-plan et avant de onPostExexute()
est touché.est-il possible que
onPostExecute()
se invoquée avant de remplir doInBackground(..)
?autant que je sache, non, à moins que vous le feriez manuellement appel
onPostExecute()
(ce qui devrait pas bien sûr).OriginalL'auteur Navid Abutorab | 2014-10-23
Vous devez vous connecter pour publier un commentaire.
Mes excuses pour la réponse tardive, mais il semble que les suspects dans mon commentaire précédent: vous êtes à la modification de
contactList
de deux threads différents.ListView
caches de l'élément de comptage et chaque fois qu'il est à la disposition de ses enfants, il va vérifier ce nombre againt le nombre d'éléments dans la carte liée. Si le comte a changé et leListView
n'était pas informé à ce sujet, une erreur est levée:Source.
En d'autres termes: c'est exactement l'erreur que vous obtenez. Dans votre scénario, le comte différence est causée par la modification de la sauvegarde des données de plus d'un thread unique, conduisant à un problème de synchronisation: le thread d'arrière-plan peut modifier le jeu de données, suspendu, et le thread d'interface utilisateur peut ensuite appeler
layoutChildren()
sans en avoir été informé sur le jeu de données change.Maintenant, sur la solution. Le plus facile est de s'assurer que vous n'êtes pas la modification de la liste qui est lié à la
ListView
's de l'adaptateur de threads différents. C'est, faites-en une copie que vous pouvez ensuite modifier librement, ou d'allouer une nouvelle liste.Donc, faire quelque chose comme cela, c'est à dire dans le
onPreExecute()
méthode de laAsyncTask
.Nouvelle liste:
Un (peu) copie:
Puis, dans
doInBackground()
, ajouter les donnéesmNewContactList
. Enfin, dansonPostExecute()
, vous pouvez:mNewContactList
etListView
.mNewContactList
à celles déjà existantescontactList
et appelnotifyDatasetChanged()
sur leListView
.OriginalL'auteur MH.
mise à jour des données et de votre carte d'appels notifyDataSetChanged() doit dans le même bloc de code.
par exemple:
Casse:
Mal de cas:
OriginalL'auteur