Mon programme effectue une activité réseau dans un fil d'arrière-plan. Avant de commencer, une boîte de dialogue de progression apparaît. La boîte de dialogue est fermée sur le gestionnaire. Tout cela fonctionne très bien, sauf lorsque l'orientation de l'écran change pendant que la boîte de dialogue est ouverte (et que le fil d'arrière-plan est en cours). À ce stade, l'application se bloque ou se bloque, ou entre dans une étape étrange où l'application ne fonctionne pas du tout tant que tous les threads n'ont pas été supprimés.
Comment gérer avec élégance le changement d'orientation de l'écran?
L'exemple de code ci-dessous correspond à peu près à ce que fait mon vrai programme:
public class MyAct extends Activity implements Runnable {
public ProgressDialog mProgress;
// UI has a button that when pressed calls send
public void send() {
mProgress = ProgressDialog.show(this, "Please wait",
"Please wait",
true, true);
Thread thread = new Thread(this);
thread.start();
}
public void run() {
Thread.sleep(10000);
Message msg = new Message();
mHandler.sendMessage(msg);
}
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mProgress.dismiss();
}
};
}
Empiler:
E/WindowManager( 244): Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager( 244): android.view.WindowLeaked: Activity MyAct has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@433b7150 that was originally added here
E/WindowManager( 244): at android.view.ViewRoot.<init>(ViewRoot.java:178)
E/WindowManager( 244): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:147)
E/WindowManager( 244): at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:90)
E/WindowManager( 244): at android.view.Window$LocalWindowManager.addView(Window.java:393)
E/WindowManager( 244): at android.app.Dialog.show(Dialog.java:212)
E/WindowManager( 244): at android.app.ProgressDialog.show(ProgressDialog.java:103)
E/WindowManager( 244): at android.app.ProgressDialog.show(ProgressDialog.java:91)
E/WindowManager( 244): at MyAct.send(MyAct.java:294)
E/WindowManager( 244): at MyAct$4.onClick(MyAct.java:174)
E/WindowManager( 244): at android.view.View.performClick(View.java:2129)
E/WindowManager( 244): at android.view.View.onTouchEvent(View.java:3543)
E/WindowManager( 244): at android.widget.TextView.onTouchEvent(TextView.java:4664)
E/WindowManager( 244): at android.view.View.dispatchTouchEvent(View.java:3198)
J'ai essayé de fermer la boîte de dialogue de progression dans onSaveInstanceState, mais cela empêche simplement un plantage immédiat. Le thread d'arrière-plan est toujours actif et l'interface utilisateur est partiellement dessinée. Besoin de tuer l'application entière avant qu'elle ne recommence à fonctionner.
la source
Réponses:
Lorsque vous changez d'orientation, Android crée une nouvelle vue. Vous obtenez probablement des plantages car votre thread d'arrière-plan essaie de changer l'état de l'ancien. (Il peut également avoir des problèmes car votre thread d'arrière-plan n'est pas sur le thread d'interface utilisateur)
Je suggère de rendre ce mHandler volatile et de le mettre à jour lorsque l'orientation change.
la source
Edit: les ingénieurs de Google ne recommandent pas cette approche, comme décrit par Dianne Hackborn (alias hackbod ) dans ce post StackOverflow . Consultez cet article de blog pour plus d'informations.
Vous devez l'ajouter à la déclaration d'activité dans le manifeste:
donc ça ressemble
Le problème est que le système détruit l'activité lorsqu'un changement de configuration se produit. Voir ConfigurationChanges .
Donc, mettre cela dans le fichier de configuration évite au système de détruire votre activité. Au lieu de cela, il appelle la
onConfigurationChanged(Configuration)
méthode.la source
orientation
, il y a beaucoup plus de raisons pour que la configuration change:keyboardHidden
(j'ai déjà édité la réponse wiki),uiMode
(par exemple, entrer ou sortir du mode voiture; changer le mode nuit), etc. Je me demande maintenant si c'est réellement une bonne réponse.J'ai trouvé une solution solide pour ces problèmes qui est conforme à la «manière Android» des choses. J'ai toutes mes opérations de longue durée en utilisant le modèle IntentService.
Autrement dit, mes activités diffusent des intentions, IntentService fait le travail, enregistre les données dans la base de données, puis diffuse des intentions collantes . La partie collante est importante, de sorte que même si l'activité a été interrompue pendant le temps après que l'utilisateur a commencé le travail et manque la diffusion en temps réel de IntentService, nous pouvons toujours répondre et récupérer les données de l'activité appelante.
ProgressDialog
s peut très bien fonctionner avec ce modèle aveconSaveInstanceState()
.Fondamentalement, vous devez enregistrer un indicateur indiquant qu'une boîte de dialogue de progression est exécutée dans le groupe d'instances enregistré. N'enregistrez pas l'objet de boîte de dialogue de progression car cela entraînerait une fuite de l'ensemble de l'activité. Pour avoir une poignée persistante dans la boîte de dialogue de progression, je la stocke en tant que référence faible dans l'objet d'application. Lors d'un changement d'orientation ou de toute autre chose qui provoque une pause de l'activité (appel téléphonique, l'utilisateur revient à la maison, etc.), puis je reprends, j'écarte l'ancienne boîte de dialogue et recrée une nouvelle boîte de dialogue dans l'activité nouvellement créée.
Pour les dialogues de progression indéfinie, c'est facile. Pour le style de barre de progression, vous devez mettre la dernière progression connue dans le bundle et toutes les informations que vous utilisez localement dans l'activité pour suivre la progression. Lors de la restauration de la progression, vous utiliserez ces informations pour relancer la barre de progression dans le même état qu'avant, puis la mettre à jour en fonction de l'état actuel des choses.
Donc, pour résumer, mettre des tâches de longue durée dans un IntentService couplé à une utilisation judicieuse de
onSaveInstanceState()
vous permet de garder efficacement la trace des dialogues et de les restaurer à travers les événements du cycle de vie de l'activité. Les bits pertinents du code d'activité sont ci-dessous. Vous aurez également besoin de logique dans votre BroadcastReceiver pour gérer les intentions collantes de manière appropriée, mais cela dépasse le cadre de cela.la source
J'ai rencontré le même problème. Mon activité doit analyser certaines données d'une URL et c'est lent. Je crée donc un fil pour le faire, puis affiche une boîte de dialogue de progression. Je laisse le fil publier un message sur le fil de l'interface utilisateur via
Handler
quand il est terminé. DansHandler.handleMessage
, j'obtiens l'objet de données (prêt maintenant) du thread et le remplis dans l'interface utilisateur. C'est donc très similaire à votre exemple.Après beaucoup d'essais et d'erreurs, il semble que j'ai trouvé une solution. Au moins maintenant, je peux faire pivoter l'écran à tout moment, avant ou après le fil. Dans tous les tests, la boîte de dialogue est correctement fermée et tous les comportements sont conformes aux attentes.
Ce que j'ai fait est illustré ci-dessous. L'objectif est de remplir mon modèle de données (
mDataObject
), puis de le remplir dans l'interface utilisateur. Devrait permettre la rotation de l'écran à tout moment sans surprise.Voilà ce qui fonctionne pour moi. Je ne sais pas si c'est la méthode "correcte" telle que conçue par Android - ils prétendent que cette "activité de destruction / recréation pendant la rotation de l'écran" rend les choses plus faciles, donc je suppose que cela ne devrait pas être trop compliqué.
Faites-moi savoir si vous voyez un problème dans mon code. Comme dit ci-dessus, je ne sais pas vraiment s'il y a un effet secondaire.
la source
onRetainNonConfigurationInstance()
etgetLastNonConfigurationInstance()
m'a aidé à résoudre mon problème. Pouces vers le haut!Le problème initialement perçu était que le code ne survivrait pas à un changement d'orientation de l'écran. Apparemment, cela a été "résolu" en demandant au programme de gérer lui-même le changement d'orientation de l'écran, au lieu de laisser le cadre de l'interface utilisateur le faire (en appelant onDestroy)).
Je dirais que si le problème sous-jacent est que le programme ne survivra pas à onDestroy (), alors la solution acceptée n'est qu'une solution de contournement qui laisse le programme avec d'autres problèmes et vulnérabilités graves. N'oubliez pas que le cadre Android indique spécifiquement que votre activité risque d'être détruite presque à tout moment en raison de circonstances indépendantes de votre volonté. Par conséquent, votre activité doit être en mesure de survivre à onDestroy () et à onCreate () pour une raison quelconque, et pas seulement un changement d'orientation de l'écran.
Si vous acceptez de gérer vous-même les changements d'orientation de l'écran pour résoudre le problème de l'OP, vous devez vérifier que les autres causes de onDestroy () n'entraînent pas la même erreur. Pouvez-vous faire cela? Sinon, je me demande si la réponse "acceptée" est vraiment très bonne.
la source
Ma solution a été d'étendre la
ProgressDialog
classe pour obtenir la mienneMyProgressDialog
.J'ai redéfini
show()
et lesdismiss()
méthodes pour verrouiller l'orientation avant d'afficherDialog
et de la déverrouiller en cas deDialog
rejet. Ainsi, lorsqueDialog
s'affiche et que l'orientation de l'appareil change, l'orientation de l'écran reste jusqu'à ce que vousdismiss()
appeliez, puis l'orientation de l'écran change en fonction des valeurs du capteur / de l'orientation de l'appareil.Voici mon code:
la source
J'ai rencontré ce même problème, et j'ai trouvé une solution qui n'impliquait pas l'utilisation de ProgressDialog et j'obtiens des résultats plus rapides.
Ce que j'ai fait, c'est créer une mise en page contenant une barre de progression.
Ensuite, dans la méthode onCreate, procédez comme suit
Ensuite, effectuez la longue tâche dans un thread et, une fois terminé, un Runnable définit la vue de contenu sur la mise en page réelle que vous souhaitez utiliser pour cette activité.
Par exemple:
C'est ce que j'ai fait, et j'ai constaté qu'il fonctionne plus rapidement que d'afficher le ProgressDialog et qu'il est moins intrusif et a une meilleure apparence à mon avis.
Cependant, si vous souhaitez utiliser ProgressDialog, cette réponse n'est pas pour vous.
la source
setContentView(R.layout.my_layout);
c'est insuffisant; vous devez configurer tous les écouteurs, réinitialiser les données, etc.J'ai découvert une solution à cela que je n'ai pas encore vue ailleurs. Vous pouvez utiliser un objet d'application personnalisé qui sait si vous avez des tâches en arrière-plan au lieu d'essayer de le faire dans l'activité qui est détruite et recréée lors d'un changement d'orientation. J'ai blogué à ce sujet ici .
la source
Application
est normalement utilisée pour maintenir un état d'application global. Je ne dis pas que cela ne fonctionne pas, mais cela semble trop compliqué. Extrait du document "Il n'est normalement pas nécessaire de sous-classer Application.". Je préfère largement la réponse de sonxurxo.Je vais apporter mon approche pour gérer ce problème de rotation. Cela peut ne pas être pertinent pour OP car il n'utilise pas
AsyncTask
, mais peut-être que d'autres le trouveront utile. C'est assez simple mais il semble faire le travail pour moi:J'ai une activité de connexion avec une
AsyncTask
classe imbriquée appeléeBackgroundLoginTask
.Dans mon
BackgroundLoginTask
je ne fais rien d'extraordinaire sauf pour ajouter un chèque nul lors de l'appelProgressDialog
de licenciement:Il s'agit de gérer le cas où la tâche d'arrière-plan se termine alors que le
Activity
n'est pas visible et, par conséquent, la boîte de dialogue de progression a déjà été fermée par laonPause()
méthode.Ensuite, dans ma
Activity
classe parent , je crée des descripteurs statiques globaux pour maAsyncTask
classe et monProgressDialog
(leAsyncTask
, étant imbriqué, peut accéder à ces variables):Cela sert à deux fins: Premièrement, cela me permet
Activity
d'accéder toujours à l'AsyncTask
objet même à partir d'une nouvelle activité post-rotation. Deuxièmement, cela me permetBackgroundLoginTask
d'accéder et de supprimer leProgressDialog
même après une rotation.Ensuite, j'ajoute ceci à
onPause()
, provoquant la disparition de la boîte de dialogue de progression lorsque notreActivity
quitte le premier plan (empêchant ce vilain crash "force close"):Enfin, j'ai les éléments suivants dans ma
onResume()
méthode:Cela permet
Dialog
de réapparaître après laActivity
recréation du.Voici toute la classe:
Je ne suis en aucun cas un développeur Android chevronné, alors n'hésitez pas à commenter.
la source
Déplacez la tâche longue vers une classe séparée. Implémentez-le comme un modèle sujet-observateur. Chaque fois que l'activité est créée, enregistrez-vous et fermez la session en vous désinscrivant avec la classe de tâches. La classe de tâches peut utiliser AsyncTask.
la source
L'astuce consiste à afficher / fermer la boîte de dialogue dans AsyncTask pendant onPreExecute / onPostExecute comme d'habitude, bien qu'en cas de changement d'orientation, créez / affichez une nouvelle instance de la boîte de dialogue dans l'activité et transmettez sa référence à la tâche.
la source
Je l'ai fait comme ça:
Vous pouvez également essayer de me faire savoir que cela fonctionne pour vous ou non
la source
Si vous créez un arrière
Service
- plan qui fait tout le gros du travail (requêtes / réponses tcp, dégroupage), leView
etActivity
peut être détruit et recréé sans fuite de fenêtre ou perte de données. Cela permet au comportement recommandé par Android, qui est de détruire une activité à chaque changement de configuration (par exemple pour chaque changement d'orientation).C'est un peu plus complexe, mais c'est le meilleur moyen d'invoquer la demande du serveur, le pré / post-traitement des données, etc.
Vous pouvez même utiliser votre
Service
pour mettre chaque demande en file d'attente sur un serveur, ce qui rend la gestion de ces choses simple et efficace.Le guide de développement contient un chapitre
Services
complet .la source
Service
est plus de travail qu'un,AsyncTask
mais peut être une meilleure approche dans certaines situations. Ce n'est pas nécessairement mieux, n'est-ce pas? Cela étant dit, je ne comprends pas comment cela résout le problème de laProgressDialog
fuite de la principaleActivity
. Où instanciez-vous leProgressDialog
? Où la rejetez-vous?J'ai une implémentation qui permet à l'activité d'être détruite lors d'un changement d'orientation d'écran, mais détruit toujours la boîte de dialogue dans l'activité recréée avec succès. j'utilise
...NonConfigurationInstance
pour attacher la tâche d'arrière-plan à l'activité recréée. Le cadre Android normal gère la recréation de la boîte de dialogue elle-même, rien n'y change.J'ai sous-classé AsyncTask en ajoutant un champ pour l'activité «propriétaire» et une méthode pour mettre à jour ce propriétaire.
Dans ma classe d'activité, j'ai ajouté un champ
backgroundTask
faisant référence à la tâche d'arrière-plan «détenue», et je mets à jour ce champ à l'aide deonRetainNonConfigurationInstance
etgetLastNonConfigurationInstance
.Suggestions d'améliorations supplémentaires:
backgroundTask
référence dans l'activité une fois la tâche terminée pour libérer la mémoire ou les autres ressources qui lui sont associées.ownerActivity
référence dans la tâche d'arrière-plan avant de détruire l'activité au cas où elle ne serait pas recréée immédiatement.BackgroundTask
interface et / ou une collection pour permettre à différents types de tâches de s'exécuter à partir de la même activité propriétaire.la source
Si vous conservez deux dispositions, tous les threads de l'interface utilisateur doivent être terminés.
Si vous utilisez AsynTask, vous pouvez facilement appeler la
.cancel()
méthode à l'intérieur de laonDestroy()
méthode de l'activité actuelle.Pour AsyncTask, lisez plus dans la section "Annulation d'une tâche" ici .
Mise à jour: condition supplémentaire pour vérifier l'état, car elle ne peut être annulée que si elle est en cours d'exécution. Notez également que la tâche AsyncTask ne peut être exécutée qu'une seule fois.
la source
J'ai essayé d'implémenter la solution de jfelectron car c'est une « solution solide à ces problèmes qui est conforme à la« manière Android »des choses », mais il a fallu un certain temps pour rechercher et rassembler tous les éléments mentionnés. Je me suis retrouvé avec cette solution légèrement différente, et je pense plus élégante, publiée ici dans son intégralité.
Utilise un IntentService déclenché à partir d'une activité pour effectuer la tâche de longue durée sur un thread distinct. Le service renvoie des intentions de diffusion collantes à l'activité qui met à jour la boîte de dialogue. L'activité utilise showDialog (), onCreateDialog () et onPrepareDialog () pour éliminer la nécessité de transmettre des données persistantes dans l'objet d'application ou le bundle savedInstanceState. Cela devrait fonctionner quelle que soit la façon dont votre application est interrompue.
Classe d'activité:
Classe IntentService:
Entrées du fichier manifeste:
avant la section application:
à l'intérieur de la section d'application
la source
Voici ma solution proposée:
void showProgressDialog()
méthode peut être ajoutée à l'interface d'écoute fragment-activité à cet effet.la source
J'ai fait face à la même situation. J'ai obtenu une seule instance pour ma boîte de dialogue de progression dans l'ensemble de l'application.
Tout d'abord, j'ai créé une classe DialogSingleton pour obtenir une seule instance (modèle Singleton)
Comme je le montre dans cette classe, j'ai la boîte de dialogue de progression comme attribut. Chaque fois que j'ai besoin d'afficher une boîte de dialogue de progression, j'obtiens l'instance unique et crée un nouveau ProgressDialog.
Une fois la tâche en arrière-plan terminée, j'appelle à nouveau l'instance unique et ferme sa boîte de dialogue.
J'enregistre l'état de la tâche en arrière-plan dans mes préférences partagées. Lorsque je fais pivoter l'écran, je demande si une tâche est en cours d'exécution pour cette activité: (onCreate)
Lorsque je commence à exécuter une tâche en arrière-plan:
Lorsque je termine d'exécuter une tâche en arrière-plan:
J'espère que ça aide.
la source
C'est une très vieille question qui est apparue dans la barre latérale pour une raison quelconque.
Si la tâche d'arrière-plan ne doit survivre que lorsque l'activité est au premier plan, la "nouvelle" solution consiste à héberger le thread d'arrière-plan (ou, de préférence,
AsyncTask
) dans un fragment conservé , comme décrit dans ce guide du développeur et de nombreuses questions et réponses .Un fragment conservé survit si l'activité est détruite pour un changement de configuration, mais pas lorsque l'activité est détruite en arrière-plan ou en pile arrière. Par conséquent, la tâche d'arrière-plan doit toujours être interrompue si elle
isChangingConfigurations()
est fausse dansonPause()
.la source
Je suis plus frais sur Android et j'ai essayé et ça a fonctionné.
la source
J'ai tout essayé. Nous avons passé des jours à expérimenter. Je ne voulais pas empêcher l'activité de tourner. Mon scénario était:
Le problème était que lors de la rotation de l'écran, chaque solution du livre avait échoué. Même avec la classe AsyncTask, qui est la bonne façon Android de gérer ces situations. Lors de la rotation de l'écran, le contexte actuel avec lequel le thread de départ travaille est parti et cela gâche la boîte de dialogue qui s'affiche. Le problème a toujours été la boîte de dialogue, quel que soit le nombre de trucs que j'ai ajoutés au code (passage de nouveaux contextes aux threads en cours d'exécution, conservation des états des threads lors des rotations, etc.). La complexité du code à la fin était toujours énorme et il y avait toujours quelque chose qui pouvait mal tourner.
La seule solution qui a fonctionné pour moi était l'astuce Activité / Dialogue. C'est simple et génial et tout est à l'épreuve de la rotation:
Au lieu de créer une boîte de dialogue et de demander à l'afficher, créez une activité qui a été définie dans le manifeste avec android: theme = "@ android: style / Theme.Dialog". Donc, cela ressemble à une boîte de dialogue.
Remplacez showDialog (DIALOG_ID) par startActivityForResult (yourActivityDialog, yourCode);
Utilisez onActivityResult dans l'activité appelante pour obtenir les résultats du thread d'exécution (même les erreurs) et mettre à jour l'interface utilisateur.
Sur votre 'ActivityDialog', utilisez des threads ou AsyncTask pour exécuter de longues tâches et onRetainNonConfigurationInstance pour enregistrer l'état de "dialogue" lors de la rotation de l'écran.
C'est rapide et fonctionne bien. J'utilise toujours des boîtes de dialogue pour d'autres tâches et la tâche AsyncTask pour quelque chose qui ne nécessite pas de boîte de dialogue constante à l'écran. Mais avec ce scénario, je choisis toujours le modèle Activité / Dialogue.
Et, je ne l'ai pas essayé, mais il est même possible d'empêcher cette activité / boîte de dialogue de tourner, lorsque le thread est en cours d'exécution, ce qui accélère les choses, tout en permettant à l'activité appelante de tourner.
la source
Intent
, ce qui est plus restrictif que celuiObject
autorisé parAsyncTask
De nos jours, il existe une manière beaucoup plus distincte de gérer ces types de problèmes. L'approche typique est:
1. Assurez-vous que vos données sont correctement séparées de l'interface utilisateur:
Tout ce qui est un processus d'arrière-plan doit être conservé
Fragment
(définissez-le avecFragment.setRetainInstance()
. Cela devient votre «stockage de données persistant» où toutes les données que vous souhaitez conserver sont conservées. Après l'événement de changement d'orientation, ilFragment
sera toujours accessible dans son original état via unFragmentManager.findFragmentByTag()
appel (lorsque vous le créez, vous devez lui attribuer une balise et non un ID car il n'est pas attaché à aView
).Consultez le guide développé sur la gestion des modifications de l'exécution pour savoir comment procéder correctement et pourquoi c'est la meilleure option.
2. Assurez-vous d'interfacer correctement et en toute sécurité entre les processus d'arrière-plan et votre interface utilisateur:
Vous devez inverser votre processus de liaison. Pour le moment, votre processus d'arrière-plan s'attache à un
View
- au lieu de cela, vousView
devriez vous attacher au processus d'arrière-plan. Cela a plus de sens, non? L'View
action de dépend du processus d'arrière-plan, tandis que le processus d'arrière-plan ne dépend pas duView
. Cela signifie changer le lien vers uneListener
interface standard . Dites votre processus (quelle que soit la classe - qu'il s'agisse d'unAsyncTask
,Runnable
ou autre) définit unOnProcessFinishedListener
, lorsque le processus est terminé, il devrait appeler cet écouteur s'il existe.Cette réponse est une belle description concise de la façon de faire des écouteurs personnalisés.
3. Liez votre interface utilisateur au processus de données chaque fois que l'interface utilisateur est créée (y compris les changements d'orientation):
Vous devez maintenant vous soucier d'interfacer la tâche d'arrière-plan avec la
View
structure actuelle . Si vous gérez correctement vos changements d'orientation (pas leconfigChanges
hack que les gens recommandent toujours), alors votreDialog
sera recréé par le système. Ceci est important, cela signifie que lors du changement d'orientation, toutes lesDialog
méthodes de votre cycle de vie sont rappelées. Donc, dans l'une de ces méthodes (onCreateDialog
c'est généralement un bon endroit), vous pouvez faire un appel comme celui-ci:Reportez-vous au cycle de vie des fragments pour décider où le réglage de l'écouteur convient le mieux à votre implémentation individuelle.
Il s'agit d'une approche générale pour fournir une solution robuste et complète au problème générique posé dans cette question. Il y a probablement quelques éléments mineurs manquants dans cette réponse en fonction de votre scénario individuel, mais c'est généralement l'approche la plus correcte pour gérer correctement les événements de changement d'orientation.
la source
j'ai trouvé et une solution plus simple pour gérer les fils lorsque l'orientation change. Vous pouvez simplement conserver une référence statique à votre activité / fragment et vérifier si sa valeur est nulle avant d'agir sur l'interface utilisateur. Je suggère également d'utiliser une prise d'essai:
la source
Si vous avez du mal à détecter les événements de changement d'orientation d'une boîte de dialogue INDÉPENDANTE D'UNE RÉFÉRENCE D'ACTIVITÉ , cette méthode fonctionne très bien. J'utilise cela parce que j'ai ma propre classe de dialogue qui peut être affichée dans plusieurs activités différentes, donc je ne sais pas toujours dans quelle activité il est affiché. et vous n'avez pas besoin d'une boîte de dialogue personnalisée (comme je l'ai fait). Vous avez cependant besoin d'une vue de contenu personnalisée pour pouvoir détecter les changements d'orientation à l'aide de cette vue particulière. Voici mon exemple:
Installer
Implémentation 1 - Dialogue
Implémentation 2 - AlertDialog.Builder
Mise en œuvre 3 - ProgressDialog / AlertDialog
la source
C'est ma solution quand je l'ai rencontrée:
ProgressDialog
n'est pas unFragment
enfant, donc ma classe personnalisée "ProgressDialogFragment
" peut s'étendre à laDialogFragment
place afin de garder la boîte de dialogue affichée pour les changements de configuration.Il existe 2 approches pour résoudre ce problème:
Première approche: effectuez l'activité qui utilise la boîte de dialogue pour conserver l'état lors du changement de configuration dans le fichier manifeste:
Cette approche n'est pas préférée par Google.
Deuxième approche: sur la
onCreate()
méthode de l'activité , vous devez conserver votreDialogFragment
en reconstruisant leProgressDialogFragment
avec le titre et le message comme suit si lesavedInstanceState
n'est pas nul:la source
Semble beaucoup trop «rapide et sale» pour être vrai, alors veuillez signaler les défauts, mais ce que j'ai trouvé fonctionnait était ...
Dans la méthode onPostExecute de ma tâche AsyncTask, j'ai simplement enveloppé le '.dismiss' pour la boîte de dialogue de progression dans un bloc try / catch (avec une capture vide), puis j'ai simplement ignoré l'exception qui a été déclenchée. Semble mal à faire mais semble qu'il n'y ait pas d'effets néfastes (au moins pour ce que je fais par la suite qui est de démarrer une autre activité en passant à la suite de ma longue requête en tant qu'extra)
la source
Activity
fait référence auDialog
. Lorsque la configuration est modifiée, la premièreActivity
est détruite, ce qui signifie que tous les champs sont définis surnull
. Mais le bas niveau faitWindowManager
également référence auDialog
(puisqu'il n'est pas encore rejeté). Le nouveauActivity
essaie de créer un nouveauDialog
(enpreExecute()
) et le gestionnaire de fenêtres déclenche une exception fatale vous empêchant de le faire. En effet, si tel était le cas, il n'y aurait aucun moyen de détruire proprement leDialog
conservant ainsi une référence à l'initialeActivity
. Ai-je raison?La solution la plus simple et la plus flexible consiste à utiliser une AsyncTask avec une référence statique à ProgressBar . Cela fournit une solution encapsulée et donc réutilisable aux problèmes de changement d'orientation. Cette solution m'a bien servi pour diverses tâches asynchrones, y compris les téléchargements Internet, la communication avec les services et les analyses de système de fichiers. La solution a été bien testée sur plusieurs versions Android et modèles de téléphones. Une démo complète peut être trouvée ici avec un intérêt spécifique pour DownloadFile.java
Je présente ce qui suit comme un exemple de concept
L'utilisation dans une activité Android est simple
la source
Lorsque vous changez d'orientation, Android supprime cette activité et crée une nouvelle activité. Je suggère d'utiliser le retrofit avec Rx java. qui gère les plantages automatiquement.
Utilisez ces méthodes lors d'un appel ultérieur.
.subscribeOn (Schedulers.io ()) .observeOn (AndroidSchedulers.mainThread ())
la source