89 votes

Comment utiliser Intent.FLAG_ACTIVITY_CLEAR_TOP pour vider la pile d'activités ?

J'ai lu plusieurs articles sur l'utilisation de ce système, mais il doit me manquer quelque chose car il ne fonctionne pas pour moi. Mon activité A a launchmode="singleTop" dans le manifeste. Elle lance l'activité B, avec launchmode="singleInstance". L'activité B ouvre un navigateur et reçoit une intention en retour, c'est pourquoi elle est en mode singleInstance. J'essaie de remplacer le bouton de retour 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 le retour du navigateur, la pile est... A,B,Navigateur,B

Je m'attends à ce que ce code change la pile en... A ... de sorte que le fait d'appuyer une nouvelle fois sur la touche retour ramène l'utilisateur à 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 retour me ramène à nouveau au navigateur !

Qu'est-ce que je rate ?

116voto

bitestar Points 797

J'ai commencé l'activité A->B->C->D. Lorsque j'appuie sur le bouton "Retour" de l'activité D, je veux revenir à l'activité A. Comme A est mon point de départ et qu'il se trouve donc déjà sur la pile, toutes les activités situées au-dessus de A sont effacées et il est impossible de revenir à une autre activité à partir de A.

Cela fonctionne effectivement 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);
}

4 votes

Cette solution consiste à fermer toutes les activités intermédiaires, mais aussi à redémarrer la RootActivity. Vous pouvez consulter la solution de @Steel_Fedex ci-dessous. Elle fait la même chose, mais ne redémarre pas la RootActivity.

0 votes

C'est la meilleure solution pour mon cas. En fait, je veulent le redémarrage de l'activité de la racine

73voto

ScouseChris Points 2522

@bitestar a la bonne solution, mais il y a une étape supplémentaire :

C'était caché dans la documentation, mais vous devez modifier l'attribut launchMode de la Activity à tout autre chose que standard . Sinon, il sera détruit et recréé au lieu d'être remis en haut.

54 votes

En fait... Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP fera exactement cela.

0 votes

Consultez la solution de Steel_fedex pour son exemple.

6 votes

Alors où est la solution de Steel_fedex ? !

26voto

Steel FedeX Points 291

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

y launchMode = "singleTask" dans le manifeste de l'activité lancée.

Il semble que cela fonctionne comme je le souhaite - l'activité ne redémarre pas et toutes les autres activités sont fermées.

0 votes

J'ai vérifié, la solution de Bitster ne fonctionne pas. Alors que cette solution a fonctionné. RootActivity n'a pas redémarré.

0 votes

Choisissez vos mots plus judicieusement. La solution Bitestar fonctionne réellement !

0 votes

SingleTask fonctionne pour moi, ainsi l'activité ne sera pas recréée, et traitera l'événement dans onNewIntent.

11voto

Darpan Points 709

Bien que cette question ait déjà suffisamment de réponses, j'ai pensé que quelqu'un voudrait savoir pourquoi ce drapeau fonctionne de cette manière particulière. Documentation Android

L'instance en cours d'exécution de l'activité B dans l'exemple ci-dessus recevra la nouvelle intention que vous lancez 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 est "multiple" (par défaut) et que vous n'avez pas défini FLAG_ACTIVITY_SINGLE_TOP dans la même intention, il sera terminé et recréé ; pour tous les autres modes de lancement ou si FLAG_ACTIVITY_SINGLE_TOP est défini, cette intention sera transmise à la onNewIntent() de l'instance actuelle.

Donc, soit,
1 . Changez le launchMode de l'activité A à quelque chose d'autre que la norme (c'est-à-dire singleTask ou autre). Ensuite, votre drapeau FLAG_ACTIVITY_CLEAR_TOP ne relancera pas votre activité A.

ou,

2 . Utilisez Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP comme votre drapeau. Il fonctionnera alors comme vous le souhaitez.

1voto

100rabh Points 4057

FLAG_ACTIVITY_NEW_TASK est le problème ici qui initie une nouvelle tâche, il suffit de le supprimer et vous avez terminé.

Je vous recommande de lire ce que fait chaque drapeau avant de travailler avec lui.

Lire ce & Drapeaux d'intention ici

1 votes

J'ai lu le drapeau, et ça semblait être ce dont j'avais besoin. Quoi qu'il en soit, la suppression de FLAG_ACTIVITY_NEW_TASK n'a aucun effet sur le résultat. C'est toujours une boucle sans fin de boutons retour... A->B, retour à A, retour à B, retour à A...

0 votes

Etes-vous sûr de la raison pour laquelle vous utilisez B comme singleInstance ? A Une activité "singleInstance" agit comme si FLAG_ACTIVITY_NEW_TASK était dans l'intention. developer.Android.com/guide/topics/fundamentals.html

0 votes

B doit recevoir l'intention rappelée par le navigateur. J'ai essayé de changer le mode de lancement en singleTask, et cela fonctionne toujours, mais la boucle du bouton retour se produit toujours.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X