web-dev-qa-db-fra.com

Problème de classement de la pile d'activités lors du lancement d'une application à partir du programme d'installation d'applications Android et à partir de l'écran d'accueil

À des fins de test uniquement, j'autorise le téléchargement et l'installation de mon application APK via une URL. Une fois téléchargé sur le téléphone, il peut être lancé avec le programme d'installation de l'application Android, qui offre à l'utilisateur la possibilité de l'installer sur son appareil, puis de l'exécuter.

Considérez si nous avons téléchargé et exécuté l'application de la manière décrite ci-dessus. L'activité principale/de lancement dans mon application est une page de connexion (Activity A). Une fois l'utilisateur authentifié, il est dirigé vers la zone principale de l'application, par exemple. Activity B. Alors maintenant, la pile d’activités de cette tâche est A > B.

J'appuie ensuite sur le bouton d'accueil du téléphone pour accéder à l'écran d'accueil Android. Je relance mon application via l'icône dans le menu, et je suis amené à Activity A, au lieu de Activity B. Soit la pile d'activités est maintenant A > B > A, soit il existe maintenant deux tâches distinctes avec les piles d'activité A > B et A respectivement. Ce que je veux, c'est être ramené à Activity B lorsque je relance l'application. Réappuyer alors que je suis dans cet état me ramènera à Activity B.

Ce comportement indésirable ne se produit que si j'ouvre d'abord l'application via l'installateur, et non pas si j'ouvre l'application via l'écran/le menu d'accueil.

J'ai examiné la manière dont les activités sont lancées par chaque mécanisme. Lorsque nous utilisons le programme d'installation de l'application, nous voyons les journaux suivants:

INFO/ActivityManager(XXXX): Starting activity: Intent { dat=file:///mnt/sdcard/download/[my app].apk cmp=com.Android.packageinstaller/.InstallAppProgress (has extras) }
INFO/ActivityManager(XXXX): Starting activity: Intent { act=Android.intent.action.MAIN flg=0x10000000 cmp=[my package]/[Activity A] }

via lanceur/écran d'accueil:

INFO/ActivityManager(XXXX): Starting activity: Intent { act=Android.intent.action.MAIN cat=[Android.intent.category.LAUNCHER] flg=0x10200000 cmp=[my package]/[Activity A] }

Une fois démarré avec le programme d'installation, nous voyons qu'il utilise l'indicateur 0x10000000, mais lorsqu'il est démarré avec le programme de lancement, nous voyons qu'il utilise 0x10200000. Il utilise également une catégorie d'intention.

Les docs nous voyons les drapeaux sont:

public static final int FLAG_ACTIVITY_NEW_TASK
Constant Value: 268435456 (0x10000000)

public static final int FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
Constant Value: 2097152 (0x00200000)

L'indicateur FLAG_ACTIVITY_RESET_TASK_IF_NEEDED (utilisé lors du lancement de l'application depuis le programme de lancement) semble généralement empêcher la création d'une nouvelle tâche, s'il en existe déjà une, et restaure la dernière activité utilisée. C'est le comportement souhaité. Pourquoi ça ne marche pas dans cette situation? Que puis-je faire pour que mon application me renvoie toujours à la dernière activité, qu'elle ait été lancée ou non par le biais du programme d'installation/de lancement de l'application?

Si j'utilise singleTask, cela me ramènera toujours à l'activité principale (Activity A) chaque fois que j'exécuterai l'application (ce qui n'est également pas souhaitable).

Voici une question que j'ai trouvée lorsqu'une personne rencontre un problème similaire (pour lequel aucune réponse n'a été acceptée): Une application perd sa capacité à se souvenir de sa pile lorsqu'elle est lancée à partir d'une autre application

EDIT: La recherche du drapeau FLAG_ACTIVITY_BROUGHT_TO_FRONT dans onCreate() de notre activité de lancement (et ensuite si elle est définie) semble résoudre le principal symptôme, mais il est clair que le problème sous-jacent persiste. Y at-il une solution plus complète?

EDIT2: le même résultat se produit lorsque vous téléchargez/exécutez l'application à partir d'Android Market. Par conséquent, certaines des informations ci-dessus peuvent ne pas être pertinentes.

50
antonyt

Ajout de la réponse fournie par antonyt:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) != 0) {
        // Activity was brought to front and not created,
        // Thus finishing this will get us to the last viewed activity
        finish();
        return;
    }

    // Regular activity creation code...
}
30
AlikElzin-kilaka

Le problème sous-jacent, je crois, est que les Intents utilisés sont différents entre le lanceur et l’installateur. Dans la mesure où vous obtenez différents indicateurs d'intention, vous obtiendrez un comportement de lancement différent. Vous pouvez utiliser les modes de lancement et obtenir un résultat cohérent, mais fondamentalement ces différentes intentions produisent des résultats différents.

Votre solution (ou quelque chose comme ceci ) est probablement votre meilleur pari.

12
Femi

Votre problème tient probablement au fait que le programme d'installation de l'application n'utilise pas la catégorie LAUNCHER, contrairement au lanceur. 

Ce bogue a été documenté ailleurs:

L'application commence toujours à l'état frais à la racine au lieu de reprendre l'état d'arrière-plan (bogue connue)

0
Nathan Fig