web-dev-qa-db-fra.com

Comment utilisez-vous Intent.FLAG_ACTIVITY_CLEAR_TOP pour effacer la pile d'activités?

J'ai lu plusieurs articles sur son utilisation, mais il me manque quelque chose car cela ne fonctionne pas pour moi. Mon activité A a launchmode = "singleTop" dans le manifeste. Il commence l'activité B, avec launchmode = "singleInstance". L'activité B ouvre un navigateur et reçoit et retourne l'intention, raison pour laquelle c'est singleInstance. J'essaie de remplacer le bouton Précédent pour que l'utilisateur soit renvoyé à l'activité A et puisse ensuite appuyer sur Retour pour quitter l'activité plutôt que de revenir à l'activité B.

// activity B
@Override
public boolean onKeyDown(int keyCode, KeyEvent event)  {
 if (Android.os.Build.VERSION.SDK_INT < Android.os.Build.VERSION_CODES.Eclair
  && keyCode == KeyEvent.KEYCODE_BACK
  && event.getRepeatCount() == 0) onBackPressed();
 return super.onKeyDown(keyCode, event);
}
@Override
public void onBackPressed() {
 startActivity(new Intent(this, UI.class)
 .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
 return;
}

Après être rentré du navigateur, la pile est ... A, B, Browser, B

Je m'attends à ce que ce code modifie la pile en ... A ... afin que l'utilisateur appuie de nouveau sur cette touche pour revenir à l'écran d'accueil.

Au lieu de cela, il semble changer la pile en ... A, B, Navigateur, B, A ... comme si ces drapeaux n'étaient pas là.

J'ai essayé d'appeler finish () dans l'activité B après startActivity, mais le bouton de retour me ramène à nouveau au navigateur!

Qu'est-ce que je rate? Je vous remercie!

75
piusvelte

@bitestar a la bonne solution, mais il reste une étape:

Il était caché dans les docs, cependant vous devez changer le launchMode du Activity en autre chose que standard. Sinon, il sera détruit et recréé au lieu d’être réinitialisé.

64
ScouseChris

J'ai commencé l'activité A-> B-> C-> D. Lorsque vous appuyez sur le bouton Précédent de l'activité DI, vous souhaitez accéder à l'activité A. Puisque A est mon point de départ, toutes les activités en haut de A sont donc effacées et vous ne pouvez pas revenir à une autre activité à partir de A. .

Cela fonctionne réellement dans mon code:

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        Intent a = new Intent(this,A.class);
        a.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(a);
        return true;
    }
    return super.onKeyDown(keyCode, event);
}       
103

Pour cela, j'utilise FLAG_ACTIVITY_CLEAR_TOP drapeau pour démarrer Intent
(sans pour autant FLAG_ACTIVITY_NEW_TASK)

et launchMode = "singleTask" dans le manifeste pour l'activité lancée.

On dirait que cela fonctionne comme j'ai besoin - l'activité ne redémarre pas et toutes les autres activités sont fermées.

19
Fedir Tsapana

Bien que cette question ait déjà suffisamment de réponses, je pensais que quelqu'un voudrait savoir pourquoi ce drapeau fonctionne de cette manière si particulière. C'est ce que j'ai trouvé dans documentation Android

L'instance actuellement en cours d'activité B dans l'exemple ci-dessus recevra la nouvelle intention que vous commencez ici dans sa méthode onNewIntent () ou sera elle-même terminée et redémarrée avec la nouvelle intention.

S'il a déclaré que son mode de lancement était "multiple" (par défaut) et que vous n'avez pas défini FLAG_ACTIVITY_SINGLE_TOP dans la même intention, le processus sera terminé et recréé. pour tous les autres modes de lancement ou si FLAG_ACTIVITY_SINGLE_TOP est défini, cette intention sera transmise à l'instance actuelle onNewIntent ().


Donc, soit,
1 . Changez le launchMode de l'activité A en autre chose que standard (c.-à-d. singleTask ou quelque chose). Puis votre drapeau FLAG_ACTIVITY_CLEAR_TOP ne redémarrera pas votre activité A.

ou,

2 . Utilisation Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP comme votre drapeau. Ensuite, cela fonctionnera comme vous le souhaitez.

10
Darpan

J'utilise trois drapeaux pour résoudre le problème:

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
                Intent.FLAG_ACTIVITY_CLEAR_TASK | 
                Intent.FLAG_ACTIVITY_NEW_TASK);
3
Houssin Boulla

Je sais qu'il existe déjà une réponse acceptée, mais je ne vois pas comment cela fonctionnerait pour l'OP, car je ne pense pas que FLAG_ACTIVITY_CLEAR_TOP ait un sens dans son cas particulier. Cet indicateur ne concerne que les activités de la même tâche . Sur la base de sa description, chaque activité est dans sa propre tâche : A, B et le navigateur.

Quelque chose le rebute peut-être, c'est que A est singleTop, alors que ça devrait être singleTask. Si A est singleTop et B démarre A, un nouveau A sera créé car A n'est pas dans la tâche de B. De la documentation pour singleTop:

"Si une instance de l'activité existe déjà en haut de la tâche actuelle , le système achemine l'intention vers cette instance ..."

Puisque B démarre A, la tâche en cours est la tâche de B, qui concerne une instance unique et ne peut donc pas inclure A. Utilisez singleTask pour obtenir le résultat souhaité car le système recherchera alors la tâche comportant A et la mettra au premier plan.

Enfin, une fois que B a démarré et que l'utilisateur appuie de nouveau sur A, le terminal opérateur ne veut voir ni B ni le navigateur. Pour ce faire, appeler finish () dans B est correct; Là encore, FLAG_ACTIVITY_CLEAR_TOP ne supprimera pas les autres activités de la tâche de A car ses autres activités sont toutes dans des tâches différentes. La pièce qui lui manquait, c'est que B devrait également utiliser FLAG_ACTIVITY_NO_HISTORY lors du déclenchement de l'intention du navigateur. Remarque: si le navigateur est déjà en cours d'exécution avant même de lancer l'application de l'OP, vous verrez bien sûr le navigateur lorsque vous appuierez de nouveau sur A. Alors vraiment tester cela, assurez-vous de sortir du navigateur avant de démarrer l'application.

2
Kevin

Ajoutez Android: noHistory = "true" dans le fichier manifeste.

<manifest >
        <activity
            Android:name="UI"
            Android:noHistory="true"/>

</manifest>
2
Ahmad Aghazadeh

j'ai appelé activity_name.this.finish() après avoir commencé une nouvelle intention et cela a fonctionné pour moi.

I tried "FLAG_ACTIVITY_CLEAR_TOP" and "FLAG_ACTIVITY_NEW_TASK"

Mais cela ne fonctionnera pas pour moi ... Je ne suggère pas cette solution pour une utilisation, mais si le paramètre flag ne fonctionne pas pour vous, vous pouvez essayer ceci .. Mais je vous recommande tout de même de ne pas l'utiliser

2
Swap-IOS-Android

FLAG_ACTIVITY_NEW_TASK est le problème ici qui lance une nouvelle tâche. Supprimez-la et vous avez terminé.

Bien, je vous recommande de lire ce que chaque drapeau fait avant de travailler avec eux

Lire this & Drapeaux d'intention ici

1
100rabh

Au départ, j’avais également eu du mal à faire fonctionner FLAG_ACTIVITY_CLEAR_TOP. Finalement, je l’ai obtenu en utilisant sa valeur (0x04000000). On dirait qu'il y a un problème avec Eclipse/Compiler. Mais malheureusement, l'activité survivante est relancée, ce qui n'est pas ce que je veux. On dirait qu'il n'y a pas de solution facile.

1
ja_chu