Je télécharge des données sur Internet en arrière-plan (j'utilise AsyncTask
) et affiche une boîte de dialogue de progression pendant le téléchargement. L'orientation change, l'activité est redémarrée, puis ma tâche AsyncTask est terminée - je veux fermer la boîte de dialogue de progression et démarrer une nouvelle activité. Mais l'appel à shutDialog lève parfois une exception (probablement parce que l'activité a été détruite et que la nouvelle activité n'a pas encore commencé).
Quelle est la meilleure façon de gérer ce type de problème (mise à jour de l'interface utilisateur à partir du thread d'arrière-plan qui fonctionne même si l'utilisateur change d'orientation)? Quelqu'un de Google a-t-il fourni une "solution officielle"?
Réponses:
Étape # 1: Faites votre
AsyncTask
unstatic
classe classe imbriquée ou une classe entièrement distincte, mais pas une classe interne (imbriquée non statique).Étape # 2: Ayez la
AsyncTask
prise sur leActivity
via un membre de données, défini via le constructeur et un setter.Étape # 3: lors de la création du
AsyncTask
, fournissez le courantActivity
au constructeur.Étape # 4: Dans
onRetainNonConfigurationInstance()
, retournez leAsyncTask
, après l'avoir détaché de l'activité d'origine, maintenant en cours.Étape # 5: Dans le
onCreate()
casgetLastNonConfigurationInstance()
contrairenull
, lancez-le sur votreAsyncTask
classe et appelez votre setter pour associer votre nouvelle activité à la tâche.Étape # 6: Ne faites pas référence au membre de données d'activité de
doInBackground()
.Si vous suivez la recette ci-dessus, tout fonctionnera.
onProgressUpdate()
etonPostExecute()
sont suspendus entre le débutonRetainNonConfigurationInstance()
et la fin du suivantonCreate()
.Voici un exemple de projet démontrant la technique.
Une autre approche consiste à abandonner le
AsyncTask
et à déplacer votre travail dans unIntentService
. Ceci est particulièrement utile si le travail à effectuer peut être long et doit se poursuivre indépendamment de ce que l'utilisateur fait en termes d'activités (par exemple, télécharger un gros fichier). Vous pouvez utiliser une diffusion ordonnéeIntent
pour que l'activité réponde au travail en cours (si elle est toujours au premier plan) ou déclencher unNotification
pour faire savoir à l'utilisateur si le travail a été effectué. Voici un article de blog avec plus d'informations sur ce modèle.la source
onRetainNonConfigurationInstance()
est obsolète et l'alternative suggérée est d'utilisersetRetainInstance()
, mais il ne retourne pas d'objet. Est-il possible de gérerasyncTask
le changement de configuration avecsetRetainInstance()
?Fragment
tenir leAsyncTask
. Ayez l'Fragment
appelsetRetainInstance(true)
sur lui-même. Ayez leAsyncTask
seul entretien avec leFragment
. Maintenant, lors d'un changement de configuration, leFragment
n'est pas détruit et recréé (même si l'activité l'est), et donc leAsyncTask
est conservé tout au long du changement de configuration.La réponse acceptée a été très utile, mais elle n'a pas de boîte de dialogue de progression.
Heureusement pour vous, lecteur, j'ai créé un exemple extrêmement complet et fonctionnel d'une AsyncTask avec une boîte de dialogue de progression !
la source
J'ai travaillé pendant une semaine pour trouver une solution à ce dilemme sans avoir recours à l'édition du fichier manifeste. Les hypothèses de cette solution sont les suivantes:
la mise en oeuvre
Vous devrez copier les deux fichiers trouvés au bas de ce message dans votre espace de travail. Assurez-vous simplement que:
Tous vos
Activity
s devraient s'étendreBaseActivity
Dans
onCreate()
,super.onCreate()
doit être appelé après avoir initialisé tous les membres auxquels votreASyncTask
s. Doit accéder . Remplacez égalementgetContentViewId()
pour fournir l'ID de mise en page du formulaire.Remplacez
onCreateDialog()
comme d'habitude pour créer des boîtes de dialogue gérées par l'activité.Voir le code ci-dessous pour un exemple de classe interne statique pour créer vos AsyncTasks. Vous pouvez stocker votre résultat dans mResult pour y accéder plus tard.
Et enfin, pour lancer votre nouvelle tâche:
C'est tout! J'espère que cette solution robuste aidera quelqu'un.
BaseActivity.java (organisez les importations vous-même)
SuperAsyncTask.java
la source
Oui.
La solution est davantage une proposition d'architecture d'application plutôt qu'un simple code .
Ils ont proposé 3 modèles de conception qui permettent à une application de fonctionner en synchronisation avec un serveur, quel que soit l'état de l'application (cela fonctionnera même si l'utilisateur termine l'application, l'utilisateur change d'écran, l'application se termine, tous les autres états possibles où une opération de données de fond pourrait être interrompue, cela le couvre)
La proposition est expliquée dans le discours sur les applications client Android REST lors de Google I / O 2010 par Virgil Dobjanschi. Il dure 1 heure, mais il vaut vraiment la peine d'être regardé.
La base de celui-ci est d'abstraire les opérations réseau à un
Service
qui fonctionne indépendamment de toutActivity
dans l'application. Si vous travaillez avec des bases de données, l'utilisationContentResolver
etCursor
vous donnerait un modèle Observer prêt à l'emploi qui est pratique pour mettre à jour l'interface utilisateur sans aucune logique supplémentaire, une fois que vous avez mis à jour votre base de données locale avec les données distantes extraites. Tout autre code post-opération serait exécuté via un rappel passé auService
(j'utilise unResultReceiver
sous classe pour cela).Quoi qu'il en soit, mon explication est en fait assez vague, vous devriez certainement regarder le discours.
la source
Bien que la réponse de Mark (CommonsWare) fonctionne bien pour les changements d'orientation, elle échoue si l'activité est détruite directement (comme dans le cas d'un appel téléphonique).
Vous pouvez gérer les changements d'orientation ET les rares événements d'activité détruits en utilisant un objet Application pour référencer votre ASyncTask.
Il y a une excellente explication du problème et de la solution ici :
Le mérite revient à Ryan d'avoir compris celui-ci.
la source
Après 4 ans, Google a résolu le problème en appelant setRetainInstance (true) dans Activity onCreate. Il préservera votre instance d'activité pendant la rotation de l'appareil. J'ai également une solution simple pour les anciens Android.
la source
vous devez appeler toutes les actions d'activité à l'aide du gestionnaire d'activité. Donc, si vous êtes dans un fil, vous devez créer un Runnable et publié à l'aide du gestionnaire d'Activitie. Sinon, votre application se bloque parfois avec une exception fatale.
la source
Voici ma solution: https://github.com/Gotchamoh/Android-AsyncTask-ProgressDialog
Fondamentalement, les étapes sont les suivantes:
onSaveInstanceState
pour enregistrer la tâche si elle est toujours en cours de traitement.onCreate
je obtenir la tâche si elle a été acceptée.onPause
je jette leProgressDialog
si elle est affichée.onResume
Je montreProgressDialog
si la tâche est toujours en cours de traitement.la source