web-dev-qa-db-fra.com

L'application redémarre plutôt que ne reprend

J'espère que quelqu'un pourra m'aider à trouver, sinon une solution, du moins une explication à un comportement.

Le problème:

Sur certains appareils, appuyer sur l'icône du lanceur entraîne la reprise de la tâche en cours, sur d'autres, l'intention de lancement initial est déclenchée (en redémarrant effectivement l'application). Pourquoi cela arrive-t-il? 

Le détail:

Lorsque vous appuyez sur le "Icône de lancement", l'application démarre normalement. En d'autres termes, une intention est lancée avec le nom de votre première variable 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 alors que l'application est déjà en cours d'exécution, l'activité en cours d'exécution dans ce processus est reprise (NOTthe Activity). Il reprend de la même manière que si vous l'aviez sélectionné dans les "tâches récentes" du menu du système d'exploitation. C’est le comportement que je veux 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 toujours lance le lancement initial Activity quel que soit le programme en cours. Je suppose que les icônes du lanceur lancent toujours l’intention "LAUNCHER".

  • Sur le Samsung Tab 2, lorsque vous appuyez sur l’icône du lanceur, si vous venez d’installer l’application, celle-ci lancera toujours la Activity initiale (identique à Xoom). Toutefois, après avoir redémarré le périphérique après l’installation, l’icône du lanceur au lieu de reprendre l'application. Je suppose que ces périphériques ajoutent des "applications installées" dans une table de recherche au démarrage du périphérique, ce qui permet aux icônes du programme de lancement de reprendre correctement les tâches en cours d'exécution?

J'ai lu beaucoup de réponses qui sound sont similaires à mon problème mais ajouter simplement Android:alwaysRetainTaskState="true" ou utiliser launchMode="singleTop" à Activity ne constitue pas la solution.

Modifier:

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

150
Graeme

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, la Activity par défaut est lancée ou, si une Task lancée par un précédent lancement est ouverte, elle le place au premier plan. Autrement dit: si, à un stade quelconque de votre navigation, vous créez un ancien Task et finish ancien, le programme de lancement ne reprendra plus votre application.

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

Mon problème a été résolu en supprimant ces drapeaux d’un couple de Intents:

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

Bien qu'il soit évident que le FLAG_ACTIVITY_NEW_TASK crée une nouvelle Task, je n'ai pas compris que la supposition ci-dessus était en vigueur. Je considérais cela comme un coupable et le retirais pour tester et j'avais toujours un problème, alors je l'ai écarté. Cependant, j'avais toujours les conditions ci-dessous:

i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)

Mon écran de démarrage commençait la "principale" Activity dans mon application en utilisant le drapeau ci-dessus. Après tout, si je devais "redémarrer" mon application et que la Activity était toujours en cours d'exécution, je préférerais de beaucoup conserver ses informations d'état.

Vous remarquerez dans la documentation il ne fait aucune mention du début d'une nouvelle Task:

Si défini, et que l'activité en cours de lancement est déjà en cours d'exécution dans le fichier tâche en cours, alors au lieu de lancer une nouvelle instance de cette activité, toutes les autres activités en plus de celle-ci seront fermées et cette intention sera transmise à l’ancienne activité (désormais la plus importante) en tant que nouvelle intention.

Par exemple, considérons une tâche comprenant les activités: A, B, C, D . Si D appelle startActivity () avec une intention résolue en composante de l’activité B, C et D seront terminés et B recevra l’intention donnée, la pile étant alors: A, B.

L'instance en cours de l'activité B dans l'exemple ci-dessus sera soit recevoir la nouvelle intention que vous commencez ici dans sa onNewIntent (), ou être elle-même terminée et redémarrée avec le nouveau intention. S'il a déclaré que son mode de lancement était "multiple" (le paramètre Par défaut) et que vous n'avez pas défini FLAG_ACTIVITY_SINGLE_TOP dans le même fichier l'intention, alors il sera fini et recréé; pour tout autre lancement modes ou si FLAG_ACTIVITY_SINGLE_TOP est défini, alors l’intention sera livré à l'instance actuelle onNewIntent ().

Ce mode de lancement peut également être utilisé à bon escient avec FLAG_ACTIVITY_NEW_TASK: si utilisé pour démarrer l'activité racine d'une tâche, cela apportera toute instance en cours de cette tâche au avant-plan, puis effacez-le à son état racine. C'est surtout utile, par exemple, lors du lancement d’une activité à partir de la notification directeur.

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

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

À ce stade, le deuxième indicateur FLAG_ACTIVITY_CLEAR_TOP est en train de redémarrer B qui se trouve dans la pile de tâches. Je suppose que cela doit détruire la Task et en commencer une nouvelle, ce qui cause mon problème, une situation très difficile à détecter si vous me le demandez! 

Donc, si toutes mes suppositions sont correctes:

  • La Launcher ne reprend que la tâche créée initialement
  • FLAG_ACTIVITY_CLEAR_TOP, S'IL REDÉMARRE LA SEULE Activity RESTANTE, RECRÉE ÉGALEMENT UNE NOUVELLE Task
14
Graeme

Le problème rencontré est dû à un problème rencontré par certains lanceurs Android depuis l'API 1. Vous trouverez des informations sur le bogue ainsi que des solutions possibles ici: https://code.google.com/p/Android/ issues/detail? id = 2373

Il s'agit d'un problème relativement courant sur les appareils Samsung, ainsi que sur les autres fabricants utilisant un lanceur/une peau personnalisé. Je n'ai pas vu le problème se produire sur un lanceur Android.

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 pile d'activités lorsque l'application est reprise par le programme de lancement. Vous pouvez confirmer que c'est le cas en cliquant sur le bouton Précédent lorsque vous reprenez l'application et que l'activité de lancement s'affiche. Vous devriez alors être amené à l'activité que vous espériez voir à la reprise de l'application.

La solution de contournement que j'ai choisi d'implémenter pour résoudre ce problème consiste à rechercher la catégorie Intent.CATEGORY_LAUNCHER et l'action Intent.ACTION_MAIN dans l'intention qui a démarré l'activité initiale. Si ces deux indicateurs sont présents et que l'activité ne se trouve 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 similaire devrait.

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

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

        finish();
        return;
    }
185
starkej2

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

En réalité, le système ajoutait l'activité lancée à la pile de tâches en cours, mais il apparaissait à l'utilisateur comme si un redémarrage s'était produit et qu'ils avaient perdu leur travail. La séquence était:

  1. Télécharger depuis Play Store (ou sideload apk)
  2. Lancer l'application depuis la boîte de dialogue Play Store: l'activité A apparaît [pile de tâches: A]
  3. Accédez à l'activité B [pile de tâches: A -> B]
  4. Appuyez sur le bouton 'Home'
  5. Lancez l'application depuis le tiroir de l'application: l'activité A apparaît! [pile 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 les applications de débogage déployées via ADB, mais uniquement dans les fichiers APK téléchargés à partir du Play Store ou téléchargés latéralement. Dans ce dernier 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 l'application lancée à froid depuis le lanceur. Je soupçonne que la tâche est semée avec une intention malformé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é divers modes de lancement d'activité , mais ces paramètres s'écartent 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 Back Stack , au bas de la page sous 'Démarrer une tâche':

Un tel filtre d'intention provoque l'affichage d'une icône et d'une étiquette pour l'activité dans le programme de lancement d'applicatifs, ce qui permet aux utilisateurs de lancer l'activité et de revenir à la tâche créée à tout moment après son lancement.

J'ai trouvé que cette réponse était pertinent et j'ai inséré ce qui suit dans la méthode 'onCreate' de mon activité racine (A) afin qu'elle reprenne correctement 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 des indicateurs d’intention d’analyse en demandant si l’activité est directement à la racine de la tâche. Il est difficile de prévoir et de tester les indicateurs d'intention avec toutes les manières possibles d'ouvrir une activité PRINCIPALE (lancement depuis la maison, bouton depuis le haut, lancement depuis le Play Store, etc.).

46
Rich Ehmer

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 est défini sur singleInstance (Android:launchMode="singleInstance"). La suppression de l'attribut launchMode a résolu mon problème.

5
Ali

Sur mon Cat s60, j'avais activé l'option "Ne pas conserver les activités" dans les options pour les développeurs. Désactiver cette option m'a permis de changer d'application sans perdre l'état des applications ...

0
ptp

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);
    }

credit: Je dois minimiser l'application Android en cliquant sur le bouton de 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 Précédent, interrompant ainsi l'activité plutôt que de la terminer.

0
Russell Chisholm