6

J'ai un problème semi-compliqué et j'espère que quelqu'un ici pourra m'aider.Android: notifyDataSetChanged() ne pas mettre à jour listview après changement d'orientation

Lors d'un événement de clic, je crée un thread et démarre une opération de longue durée basée sur la méthode this. Une fois la tâche longue est terminée, il fait un rappel à une autre méthode, qui fait un poste au gestionnaire:

@Override 
public void contentSearchModelChanged(Model_ContentSearch csm, ArrayList<Class_Reminder> newRemindersList) { 
    remindersList = newRemindersList; 
    mHandler.post(mUpdateDisplayRunnable); 
} 

Ce qui appelle une Runnable:

// post this to the Handler when the background thread completes 
private final Runnable mUpdateDisplayRunnable = new Runnable() { 
    public void run() { 
    updateDisplay(); 
    } 
}; 

Enfin, voici ce que mon La méthode updateDisplay() est en cours de réalisation:

private void updateDisplay() { 
    if (csModel.getState() != Model_ContentSearch.State.RUNNING) { 
     if(remindersList != null && remindersList.size() > 0){ 
       r_adapter = new ReminderAdapater(Activity_ContentSearch.this, remindersList, thisListView); 
       thisListView.setAdapter(r_adapter); 
       r_adapter.notifyDataSetChanged(); 
     } 
    } 
} 

Ceci fonctionne parfaitement lorsque je le fais normalement. Cependant, si je change d'orientation pendant que l'opération de longue durée est en cours, cela ne fonctionne pas. Cela rend le rappel correctement, et la liste des rappels contient des éléments. Mais quand il arrive à cette ligne:

r_adapter.notifyDataSetChanged(); 

Rien ne se passe. La chose étrange est, si je fais un autre soumettre et l'ai fait courir le processus entier encore (sans changer l'orientation), il actualise réellement la vue deux fois, une fois pour le soumettre précédent et encore pour le prochain. Ainsi, la vue est mise à jour une fois avec les résultats du premier envoi, puis de nouveau avec les résultats de la seconde soumission une seconde plus tard. Ainsi, l'adaptateur DID obtient les données, il ne rafraîchit pas la vue. Je sais que cela a quelque chose à voir avec le changement d'orientation, mais je ne peux pas comprendre pourquoi. Quelqu'un peut-il aider? Ou, quelqu'un peut-il suggérer une autre méthode de gestion des threads avec des changements d'orientation?

Bara

Répondre

6

Le problème est que lorsque vous modifiez des orientations est filé à partir du début d'une nouvelle activité (onCreate). Votre processus de longue durée permet de gérer l'ancienne activité (qui n'est plus visible). Vous mettez à jour correctement l'ancienne activité mais comme elle n'est plus à l'écran, vous ne la voyez plus.

Ce n'est pas un problème facile à résoudre. Il y a une bibliothèque qui peut vous aider. Il s'appelle DroidFu. Voici un blog qui (beaucoup plus de précision que I) décrit la cause profonde de ce que vous voyez et comment la bibliothèque DroidFu la combat: http://brainflush.wordpress.com/2009/11/16/introducing-droid-fu-for-android-betteractivity-betterservice-and-betterasynctask/

Edit: (Ajout de code pour le suivi de l'activité actif)

En votre classe d'application ajouter ceci:

private Activity _activeActivity; 
public void setActiveActivity(Activity activity) { 
    _activeActivity = activity; 
} 
public Activity getActiveActivity() { 
    return _activeActivity; 
} 

Dans vos activités, ajoutez:

@Override 
public void onResume() { 
    super.onResume(); 
    ((MyApplicationClassName)getApplication()).setActiveActivity(this); 
} 

maintenant, vous pouvez obtenir le activi actif ty en appelant MyApplicationClassName.getActiveActivity();

Ce n'est pas ainsi que DroidFu le fait. DroidFu définit l'activité active dans onCreate mais je ne pense pas que ce soit très robuste.

+0

Hmm ... cela semble très utile, mais il ne semble pas y avoir beaucoup de documentation? Je détesterais changer mon implémentation en utilisant DroidFu et ne pas savoir comment résoudre un problème car ce n'est pas la façon "typique" de faire les choses. – Bara

+0

Oui, il semble que ce soit une vieille bibliothèque abandonnée mais la prémisse semble saine. Vous pouvez le faire sans utiliser la bibliothèque. Fondamentalement, l'objet Application conserve une trace de l'activité active (en utilisant onResume). Ensuite, lorsque vous êtes prêt à notifier votre adaptateur, vous obtenez l'activité active de l'application, vérifiez s'il s'agit d'une instance de votre activité attendue et si c'est le cas, transtypez et notifiez. –

+0

Quel est exactement le code pour le suivi de "l'activité active"? C'est-à-dire, devrais-je faire quelque chose comme CurrentActivity act = new CurrentActivity(); puis passer acte à la classe Application? – Bara

1

J'ai eu un problème similaire, ayant un thread sendEmptyMessage fastidieux à un gestionnaire, qui à son tour appelé notifyDataSetChanged sur un ListAdapter. Cela a bien fonctionné jusqu'à ce que je change d'orientation.

Je l'ai résolu en déclarant un deuxième gestionnaire dans le thread d'interface utilisateur et en faisant le premier gestionnaire sendEmptyMessage à ce gestionnaire, qui à son tour appelé notifyDataSetChanged sur le ListAdapter. Et ayant le ListAdapter déclaré comme statique.

Je suis un débutant donc je ne sais pas si elle est une solution laid, mais ça a marché pour moi ...

De Description de Jere.Jones Je suppose que cela fonctionne comme: Le processus long sendEmptyMessage au handle de l'ancienne Activity, qui envoie à son tour sendEmptyMessage au handle dans la nouvelle Activity.

Questions connexes