App redémarre plutôt que de reprendre

J’espère que quelqu’un peut m’aider à comprendre, sinon une solution, au moins une explication d’un comportement.

Le problème:

Sur certains appareils, en appuyant sur l’icône du lanceur, la tâche en cours reprend, sur d’autres, le lancement initial est déclenché (redémarrage effectif de l’application). Pourquoi cela arrive-t-il?

Le détail:

Lorsque vous appuyez sur l’icône “Launcher Icon”, l’application démarre normalement. C’est-à-dire que je suppose qu’un Intent est lancé avec le nom de votre première Activity avec l’action android.intent.action.MAIN et la catégorie android.intent.category.LAUNCHER . Cela ne peut pas toujours être le cas cependant:

Sur la majorité des appareils, si vous appuyez sur l’icône du lanceur après le lancement de l’application, l’activité en cours de ce processus est reprise ( PAS l’ Activity initiale). Il reprend de la même manière que si vous l’aviez sélectionné dans les “Tâches récentes” du menu OS. C’est le comportement que je souhaite sur tous les appareils.

Cependant, sur d’autres périphériques sélectionnés, un comportement différent se produit:

  • Sur le Motorola Xoom, lorsque vous appuyez sur l’icône du lanceur, l’application lance toujours l’ Activity lancement initiale, quel que soit le mode d’exécution en cours. Je suppose que les icons du lanceur lancent toujours l’intention “LAUNCHER”.

  • Sur l’onglet Samsung 2, lorsque vous appuyez sur l’icône du lanceur, si vous venez d’installer l’application, celle-ci lancera toujours l’ Activity initiale (Identique à Xoom). Cependant, après le redémarrage de l’appareil, l’icône du lanceur apparaîtra. au lieu de cela reprendre l’application. Je suppose que ces appareils ajoutent des «applications installées» dans une table de recherche au démarrage du périphérique, ce qui permet aux icons du lanceur de reprendre correctement les tâches en cours?

J’ai lu beaucoup de réponses qui ressemblent à mon problème, mais simplement append android:alwaysRetainTaskState="true" ou utiliser launchMode="singleTop" pour l’ Activity ne sont pas la solution.

Modifier:

Après le lancement le plus récent de cette application, nous constatons que ce comportement a commencé à se produire sur tous les périphériques après le premier redémarrage. Ce qui me semble dingue mais à travers le processus de redémarrage, je ne peux pas vraiment trouver ce qui ne va pas.

Le comportement que vous rencontrez est dû à un problème qui existe dans certains lanceurs Android depuis l’API 1. Vous pouvez trouver des détails sur le bogue ainsi que des solutions possibles ici: https://code.google.com/p/android/issues/ détail? id = 2373 .

C’est un problème relativement courant sur les appareils Samsung, ainsi que sur les autres fabricants qui utilisent un lanceur / skin personnalisé. Je n’ai pas vu le problème se produire sur un lanceur Android stock.

Fondamentalement, l’application ne redémarre pas complètement, mais votre activité de lancement est démarrée et ajoutée en haut de la stack d’activités lorsque l’application est reprise par le lanceur. Vous pouvez confirmer que c’est le cas en cliquant sur le bouton Retour lorsque vous reprenez l’application et que vous voyez l’activité de lancement. Vous devriez alors être amené à l’activité que vous vous attendiez à voir lorsque vous avez repris l’application.

La solution de contournement que j’ai choisi d’implémenter pour résoudre ce problème consiste à vérifier la catégorie Intent.CATEGORY_LAUNCHER et l’action Intent.ACTION_MAIN dans l’intention qui démarre l’activité initiale. Si ces deux indicateurs sont présents et que l’activité n’est pas à la racine de la tâche (ce qui signifie que l’application était déjà en cours d’exécution), j’appelle finish () sur l’activité initiale. Cette solution exacte peut ne pas fonctionner pour vous, mais quelque chose de semblable devrait.

Voici ce que je fais dans onCreate () de l’activité initiale / lancement:

  if (!isTaskRoot() && getIntent().hasCategory(Intent.CATEGORY_LAUNCHER) && getIntent().getAction() != null && getIntent().getAction().equals(Intent.ACTION_MAIN)) { finish(); return; } 

Cette question est toujours d’actualité en 2016. Aujourd’hui, un testeur d’assurance qualité a signalé une application de mon redémarrage plutôt que de reprendre depuis le lanceur d’actions dans Android M.

En réalité, le système ajoutait l’activité lancée à la stack de tâches en cours, mais il semblait à l’utilisateur que le redémarrage s’était produit et qu’il avait perdu son travail. La séquence était:

  1. Télécharger depuis play store (ou sideload apk)
  2. Lancer l’application à partir de la boîte de dialog Play Store: l’activité A apparaît [stack de tâches: A]
  3. Naviguez vers l’activité B [stack de tâches: A -> B]
  4. Appuyez sur le bouton “Home”
  5. Lancer l’application à partir du tiroir d’applications: l’activité A apparaît! [stack de tâches: A -> B -> A] (l’utilisateur peut appuyer sur le bouton «Retour» pour accéder à l’activité «B» à partir d’ici)

Remarque: ce problème ne se manifeste pas pour le débogage de l’APK déployé via ADB, uniquement dans les fichiers APK téléchargés depuis le Play Store ou téléchargés. Dans ces derniers cas, l’intention de lancement de l’étape 5 contenait l’indicateur Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT , mais pas dans les cas de débogage. Le problème disparaît une fois que l’application a été démarrée à froid depuis le lanceur. Mon soupçon est que la tâche est semée avec une intention mal formée (plus précisément, non standard) qui empêche le comportement de lancement correct jusqu’à ce que la tâche soit entièrement effacée.

J’ai essayé différents modes de lancement d’activité , mais ces parameters diffèrent trop du comportement standard auquel l’utilisateur s’attendrait: reprendre la tâche à l’activité B. Voir la définition suivante du comportement attendu dans le guide des tâches et de la stack , en bas de la page sous ‘Démarrer une tâche’:

Un filtre d’intention de ce type provoque l’affichage d’une icône et d’un libellé de l’activité dans le programme de lancement de l’application, permettant aux utilisateurs de lancer l’activité et de revenir à la tâche créée à tout moment après son lancement.

J’ai trouvé cette réponse pertinente et j’ai inséré ce qui suit dans la méthode ‘onCreate’ de mon activité racine (A) afin qu’elle reprenne de manière appropriée lorsque l’utilisateur ouvre l’application.

  /** * Ensure the application resumes whatever task the user was performing the last time * they opened the app from the launcher. It would be preferable to configure this * behavior in AndroidMananifest.xml activity settings, but those settings cause drastic * undesirable changes to the way the app opens: singleTask closes ALL other activities * in the task every time and alwaysRetainTaskState doesn't cover this case, incredibly. * * The problem happens when the user first installs and opens the app from * the play store or sideloaded apk (not via ADB). On this first run, if the user opens * activity B from activity A, presses 'home' and then navigates back to the app via the * launcher, they'd expect to see activity B. Instead they're shown activity A. * * The best solution is to close this activity if it isn't the task root. * */ if (!isTaskRoot()) { finish(); return; } 

UPDATE: a déplacé cette solution loin de l’parsing des indicateurs d’intention à l’interrogation si l’activité est directement à la racine de la tâche. Les indicateurs d’intention sont difficiles à prédire et à tester avec les différentes manières d’ouvrir une activité MAIN (lancement à partir de chez vous, lancement à partir du bouton «Démarrer», lancement depuis Play Store, etc.).

Aha! (tldr; voir les déclarations en gras en bas)

J’ai trouvé le problème … je pense.

Donc, je vais commencer par une supposition. Lorsque vous appuyez sur le lanceur, il lance l’ Activity par défaut ou, si une Task lancée par un lancement précédent est ouverte, la met au premier plan. En d’autres termes, si à tout moment de votre navigation, vous créez une nouvelle Task et finish l’ancienne, le lanceur ne reprendra plus votre application.

Si cette supposition est vraie, je suis sûr que cela devrait être un bogue, étant donné que chaque Task est dans le même processus et est tout aussi valide qu’un candidat de CV que le premier créé?

Mon problème alors, a été résolu en supprimant ces drapeaux à partir de deux Intents :

 i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK ); 

Bien qu’il soit évident que FLAG_ACTIVITY_NEW_TASK crée une nouvelle Task , je n’ai pas FLAG_ACTIVITY_NEW_TASK que cette supposition était effective. Je l’ai considéré comme un coupable et l’ai enlevé pour tester et j’avais toujours un problème alors je l’ai rejeté. Cependant, j’avais toujours les conditions ci-dessous:

 i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) 

Mon écran de démarrage commençait l’activité “principale” dans mon application en utilisant le drapeau ci-dessus. Après tout, si j’avais “redémarré” mon application et que l’ Activity était toujours en cours, je préférerais de loin conserver ses informations d’état.

Vous remarquerez dans la documentation qu’il ne fait aucune mention du démarrage d’une nouvelle Task :

Si elle est définie et que l’activité en cours d’exécution est déjà en cours d’exécution dans la tâche en cours, toutes les autres activités seront fermées au lieu de lancer une nouvelle instance de cette activité et cette intention sera transmise à (maintenant activée). top) ancienne activité en tant que nouvelle intention.

Par exemple, considérons une tâche composée des activités suivantes: A, B, C, D. Si D appelle startActivity () avec une intention qui résout le composant de l’activité B, alors C et D seront terminés et B recevra l’intention donnée , résultant en la stack étant maintenant: A, B.

L’instance en cours d’exécution de l’activité B dans l’exemple ci-dessus recevra soit la nouvelle intention que vous commencez ici dans sa méthode onNewIntent (), soit sera elle-même terminée et redémarrée avec la nouvelle intention. S’il a déclaré que son mode de lancement est “multiple” (valeur par défaut) et que vous n’avez pas défini FLAG_ACTIVITY_SINGLE_TOP dans le même but, il sera alors terminé et recréé; pour tous les autres modes de lancement ou si FLAG_ACTIVITY_SINGLE_TOP est défini, cette intention sera transmise à onNewIntent () de l’instance actuelle.

Ce mode de lancement peut également être utilisé conjointement avec FLAG_ACTIVITY_NEW_TASK: s’il est utilisé pour démarrer l’activité racine d’une tâche, il met au premier plan toute instance en cours d’exécution de cette tâche, puis la désactive à son état racine. Cela est particulièrement utile, par exemple, lors du lancement d’une activité à partir du gestionnaire de notifications.

Donc, j’ai eu la situation décrite ci-dessous:

  • A B lancé avec FLAG_ACTIVITY_CLEAR_TOP , A termine.
  • B souhaite redémarrer un service, il envoie donc l’utilisateur à A qui a la logique de redémarrage du service et l’interface utilisateur (aucun indicateur).
  • A lance B avec FLAG_ACTIVITY_CLEAR_TOP, A termine.

A ce stade, le deuxième indicateur FLAG_ACTIVITY_CLEAR_TOP redémarre B qui se trouve dans la stack de tâches. Je suppose que cela doit détruire la Task et en commencer une nouvelle, causant mon problème, ce qui est une situation très difficile à repérer si vous me le demandez!

Donc, si toutes mes suppositions sont correctes:

  • Le Launcher ne reprend que la tâche créée initialement
  • FLAG_ACTIVITY_CLEAR_TOP redémarre la seule Activity restante, FLAG_ACTIVITY_CLEAR_TOP recrée également une nouvelle Task

J’ai eu le même problème sur les appareils Samsung. Après avoir beaucoup cherché, aucune de ces réponses n’a fonctionné pour moi. J’ai trouvé que dans le fichier AndroidManifest.xml , launchMode était défini sur singleInstance ( android:launchMode="singleInstance" ). La suppression de l’atsortingbut launchMode résolu mon problème.

Solution pour les personnes qui n’ont aucune idée de la programmation et de l’expérience de ce problème sur leur téléphone Android. Cela se produit principalement en raison de la mise à niveau de la version Android (seulement mon hypothèse). Après la mise à niveau, toutes vos applications sont optimisées pour utiliser moins de batterie. Mais cela ralentit votre appareil.

Comment résoudre

Accédez aux parameters >> Applications >> Paramètres des applications (recherchez les parameters signés n’importe où sur l’écran – il est différent sur différents appareils) >> optimisation de la batterie (ou opti similaire [entrez la description de l’image ici] [1] activée) >> les applications à l’état “non optimisé” (doivent faire 1 par 1 manuellement – peuvent être autorisées / interdites sur certains téléphones). Votre application de lanceur doit être “non optimisée” (lanceur d’interface utilisateur Zen dans mon cas – c’est le coupable, je suppose – vous pouvez essayer d’optimiser / ne pas optimiser et redémarrer une application différente si vous en avez le temps). Maintenant, redémarrez votre téléphone. (pas besoin de réinitialiser les données / mode sans échec ou un problème quelconque)

Essayez le multitâche maintenant. 🙂 Appuyez sur l’icône du lanceur pour que la tâche en cours reprenne. 🙂 Votre appareil deviendra Ne vous inquiétez pas de la batterie, il va se vider de toute façon.

Cette solution a fonctionné pour moi:

  @Override public boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { Intent startMain = new Intent(Intent.ACTION_MAIN); startMain.addCategory(Intent.CATEGORY_HOME); startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(startMain); return false; } else return super.onKeyUp(keyCode, event); } 

crédit: je dois minimiser l’application Android sur le clic du bouton retour

peut ne pas fonctionner sur tous les périphériques, mais crée avec succès le comportement du bouton d’accueil lorsque vous appuyez sur le bouton Retour, ce qui stoppe l’activité plutôt que de la terminer.

Inestimable pour vos utilisateurs. Le CV parfait même après des semaines de séance dans la liste des applications récemment utilisées.

Cela ressemble à un CV pour l’utilisateur, mais en réalité, c’est un début complet.

Arrière-plan: La mémoire utilisée par les applications de l’activité principale qui n’ont pas démarré de tâche est facile à récupérer. Le système d’exploitation peut simplement redémarrer l’application avec le paquet d’origine passé à onCreate. Vous pouvez cependant append au bundle d’origine dans onSaveInstanceState Ainsi, lorsque votre application est redémarrée par le système d’exploitation, vous pouvez restaurer l’état de l’instance et personne ne sait si l’application a redémarré ou repris. Prenons par exemple le programme de carte classique. L’utilisateur se déplace sur la carte et appuie ensuite sur la touche d’accueil. Deux semaines plus tard, cette application de cartographie est toujours dans la liste des applications récentes avec Facebook, Pandora, et bonbons crush. Le système d’exploitation enregistre non seulement le nom de l’application pour les applications récemment utilisées, mais enregistre également le lot d’origine utilisé pour démarrer l’application. Cependant, le programmeur a codé la méthode onSaveInstanceState pour que le bundle orignal contienne désormais tous les matériaux et informations nécessaires à la construction de l’application, de sorte qu’il semble avoir été repris.

Exemple: enregistrez la position actuelle de la caméra dans onSaveInstanceState, mais vous devez simplement redémarrer l’application plusieurs semaines plus tard à partir de la liste des applications récentes.

 @Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); // save the current camera position; if (mMap != null) { savedInstanceState.putParcelable(CAMERA_POSITION, mMap.getCameraPosition()); } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // get the exact camera position if the app was unloaded. if (savedInstanceState != null) { // get the current camera position; currentCameraPosition = savedInstanceState .getParcelable(CAMERA_POSITION); } 

Remarque: vous pouvez également utiliser la méthode onRestoreInstanceState mais je trouve plus facile de restaurer l’instance dans onCreate .

C’est probablement ce qui se passe dans votre application. Sur certains appareils, votre application est déchargée pour libérer de la mémoire. Oui, il y a des drapeaux qui aident, mais les drapeaux ne captent pas toutes les nuances de votre application et les drapeaux ne vous garderont pas en vie pendant des semaines comme le fera onSaveInstanceState . Vous devez coder le parfait résumé de deux semaines. Ce ne sera pas une tâche facile pour l’application complexe, mais nous sums derrière vous et sums là pour vous aider.

Bonne chance