AsyncTask
est une bonne chose pour exécuter des tâches complexes dans un autre thread.
Mais lorsqu'il y a un changement d'orientation ou un autre changement de configuration alors que le AsyncTask
est toujours en cours d'exécution, le courant Activity
est détruit et redémarré. Et comme l'instance de AsyncTask
est connectée à cette activité, elle échoue et provoque une fenêtre de message "Forcer la fermeture".
Donc, je recherche une sorte de "meilleure pratique" pour éviter ces erreurs et empêcher AsyncTask d'échouer.
Ce que j'ai vu jusqu'à présent, c'est:
- Désactivez les changements d'orientation (ce n'est certainement pas la façon dont vous devez gérer cela.)
- Laisser la tâche survivre et la mettre à jour avec la nouvelle instance d'activité via
onRetainNonConfigurationInstance
- Il suffit d'annuler la tâche lorsque le
Activity
est détruit et de le redémarrer lorsque leActivity
est de nouveau créé. - Lier la tâche à la classe d'application au lieu de l'instance d'activité.
- Une méthode utilisée dans le projet "tablettes" (via onRestoreInstanceState)
Quelques exemples de code:
Android AsyncTasks lors d'une rotation d'écran, partie I et partie II
Pouvez-vous m'aider à trouver la meilleure approche qui résout le problème au mieux et qui est également facile à mettre en œuvre? Le code lui-même est également important car je ne sais pas comment résoudre ce problème correctement.
la source
Réponses:
Ne pas utiliser
android:configChanges
pour résoudre ce problème. C'est une très mauvaise pratique.Ne pas utiliser
Activity#onRetainNonConfigurationInstance()
non plus . Ceci est moins modulaire et pas bien adapté auxFragment
applications basées.Vous pouvez lire mon article décrivant comment gérer les modifications de configuration à l'aide de
Fragment
s. Cela résout bien le problème de la conservation d'AsyncTask
un changement de rotation. Vous devez essentiellement héberger votreAsyncTask
intérieurFragment
, appelersetRetainInstance(true)
leFragment
, et rapporter laAsyncTask
progression / les résultats de celui-ciActivity
via le fichier conservéFragment
.la source
TabActivity
. Pour être honnête, je ne sais pas pourquoi nous en parlons même ... tout le monde convient queFragment
c'est la voie à suivre. :)Je résous généralement cela en demandant à mes AsyncTasks de déclencher des intentions de diffusion dans le rappel .onPostExecute (), afin qu'ils ne modifient pas l'activité qui les a démarrés directement. Les activités écoutent ces émissions avec des récepteurs de diffusion dynamiques et agissent en conséquence.
De cette façon, les AsyncTasks n'ont pas à se soucier de l'instance Activity spécifique qui gère leur résultat. Ils "crient" juste quand ils ont terminé, et si une activité est à peu près à ce moment (est active et focalisée / est dans son état de reprise) qui s'intéresse aux résultats de la tâche, alors elle sera gérée.
Cela implique un peu plus de temps système, car le runtime doit gérer la diffusion, mais cela ne me dérange généralement pas. Je pense que l'utilisation de LocalBroadcastManager au lieu du système par défaut accélère un peu les choses.
la source
Voici un autre exemple d'AsyncTask qui utilise un
Fragment
pour gérer les changements de configuration d'exécution (comme lorsque l'utilisateur fait pivoter l'écran) avecsetRetainInstance(true)
. Une barre de progression déterminée (régulièrement mise à jour) est également présentée.L'exemple est en partie basé sur les documents officiels, Conservation d'un objet lors d'un changement de configuration .
Dans cet exemple, le travail nécessitant un fil d'arrière-plan est le simple chargement d'une image depuis Internet dans l'interface utilisateur.
Alex Lockwood semble avoir raison de dire que lorsqu'il s'agit de gérer les changements de configuration d'exécution avec AsyncTasks, l'utilisation d'un «fragment conservé» est la meilleure pratique.
onRetainNonConfigurationInstance()
devient obsolète dans Lint, dans Android Studio. La documentation officielle nous avertit de ne pas utiliserandroid:configChanges
, de Gérer vous-même le changement de configuration , ...Ensuite, il y a la question de savoir si l'on doit utiliser une AsyncTask pour le thread d'arrière-plan.
La référence officielle d'AsyncTask prévient ...
Vous pouvez également utiliser un service, un chargeur (en utilisant un CursorLoader ou AsyncTaskLoader) ou un fournisseur de contenu pour effectuer des opérations asynchrones.
Je divise le reste du message en:
La procédure
Commencez avec une AsyncTask de base comme classe interne d'une activité (il n'est pas nécessaire que ce soit une classe interne, mais ce sera probablement pratique). À ce stade, AsyncTask ne gère pas les modifications de configuration d'exécution.
Ajoutez une classe imbriquée RetainedFragment qui étend la classe Fragement et n'a pas sa propre interface utilisateur. Ajoutez setRetainInstance (true) à l'événement onCreate de ce fragment. Fournissez des procédures pour définir et obtenir vos données.
Dans la classe d'activité la plus externe, onCreate () gère le RetainedFragment: référencez-le s'il existe déjà (au cas où l'activité redémarre); créez-le et ajoutez-le s'il n'existe pas; Ensuite, s'il existait déjà, récupérez les données de RetainedFragment et définissez votre interface utilisateur avec ces données.
Lancer l'AsyncTask depuis l'interface utilisateur
Ajoutez et codez une barre de progression déterminée:
Tout le code pour la procédure ci-dessus
Disposition des activités.
L'activité avec: classe interne AsyncTask sous-classée; classe interne sous-classée RetainedFragment qui gère les changements de configuration d'exécution (par exemple, lorsque l'utilisateur fait pivoter l'écran); et une mise à jour de la barre de progression déterminée à intervalles réguliers. ...
Dans cet exemple, la fonction de bibliothèque (référencée ci-dessus avec le préfixe de package explicite com.example.standardapplibrary.android.Network) qui fonctionne vraiment ...
Ajoutez toutes les autorisations requises par votre tâche d'arrière-plan à AndroidManifest.xml ...
Ajoutez votre activité à AndroidManifest.xml ...
la source
Récemment, j'ai trouvé une bonne solution ici . Il est basé sur l'enregistrement d'un objet de tâche via RetainConfiguration. De mon point de vue, la solution est très élégante et quant à moi j'ai commencé à l'utiliser. Vous avez juste besoin d'imbriquer votre asynctask de la basetask et c'est tout.
la source
Sur la base de la réponse @Alex Lockwood et des réponses @William & @quickdraw mcgraw sur cet article: Comment gérer les messages du gestionnaire lorsque l'activité / le fragment est suspendu , j'ai écrit une solution générique.
De cette façon, la rotation est gérée, et si l'activité passe en arrière-plan pendant l'exécution de la tâche asynchrone, l'activité recevra les rappels (onPreExecute, onProgressUpdate, onPostExecute et onCancelled) une fois reprise, donc aucune IllegalStateException ne sera levée (voir Comment gérer le gestionnaire messages lorsque l'activité / le fragment est en pause ).
Ce serait super d'avoir le même mais avec des types d'arguments génériques, comme une AsyncTask (par exemple: AsyncTaskFragment <Params, Progress, Result>), mais je n'ai pas réussi à le faire rapidement et n'ai pas le temps pour le moment. Si quelqu'un veut faire l'amélioration, n'hésitez pas!
Le code:
Vous aurez besoin du PauseHandler:
Exemple d'utilisation:
la source
Vous pouvez utiliser des chargeurs pour cela. Vérifier Doc ici
la source
Pour ceux qui souhaitent esquiver les fragments, vous pouvez conserver l'AsyncTask en cours d'exécution sur les changements d'orientation à l'aide de onRetainCustomNonConfigurationInstance () et du câblage.
(Notez que cette méthode est l'alternative à la méthode obsolète onRetainNonConfigurationInstance () ).
On dirait que cette solution n'est pas fréquemment mentionnée. J'ai écrit un exemple simple en cours d'exécution pour illustrer.
À votre santé!
la source
J'ai implémenté une bibliothèque qui peut résoudre les problèmes de pause d'activité et de récréation pendant l'exécution de votre tâche.
Vous devez implémenter
AsmykPleaseWaitTask
etAsmykBasicPleaseWaitActivity
. Votre activité et votre tâche en arrière-plan fonctionneront bien même si vous faites pivoter l'écran et basculez entre les applicationsla source
SOLUTION DE CONTOURNEMENT RAPIDE (non recommandé)
Pour éviter qu'une activité se détruise et se crée elle-même, il faut déclarer votre activité dans le fichier manifeste: android: configChanges = "orientation | keyboardHidden | screenSize
Comme il est mentionné dans la documentation
la source