Suppression d'une activité de la pile d'historique

382

Mon application affiche une activité d'inscription la première fois que l'utilisateur exécute l'application, ressemble à:

  1. ActivitySplashScreen (bienvenue dans le jeu, ouvrir un compte?)
  2. ActivitySplashScreenSignUp (super, remplissez cette info)
  3. ActivityGameMain (écran principal du jeu)

les activités se lancent donc exactement dans cet ordre, lorsque l'utilisateur clique sur un bouton sur chaque écran.

Lorsque l'utilisateur passe de l'activité # 2 à # 3, est-il possible d'effacer complètement # 1 et # 2 de la pile d'historique? Je voudrais que si l'utilisateur est au n ° 3 et appuie sur le bouton de retour, il passe simplement à l'écran d'accueil, au lieu de revenir à l'écran de démarrage.

Je pense que je peux accomplir cela avec des tâches (c'est-à-dire commencer une nouvelle tâche sur # 3) mais je voulais voir s'il y avait une méthode plus simple,

Merci

marque
la source
Après avoir été dans l'écran d'accueil, lorsque l'utilisateur reprend votre application, est-ce que cela l'amène à ActivitySplashScreen ou ActivityGameMain?
Tamil

Réponses:

632

Vous pouvez y parvenir en définissant l' android:noHistory attribut sur "true"dans les <activity>entrées pertinentes de votre AndroidManifest.xmlfichier. Par exemple:

<activity
    android:name=".AnyActivity"
    android:noHistory="true" />
Aitor Gómez
la source
12
C'est la meilleure façon de procéder.
shkschneider
22
De manière équivalente, vous pouvez utiliser FLAG_ACTIVITY_NO_HISTORY.
Timmmm
34
Comment puis-je y parvenir à partir du code? Parce que je ne veux pas faire ça tout le temps. Je voudrais supprimer une activité donnée de l'histoire uniquement sous certaines conditions.
Namratha
8
Sachez simplement que l'utilisation de l'attribut noHistory mettra fin à cette activité, ce qui pourrait provoquer un comportement inattendu avec la connexion G + par exemple. Voir: stackoverflow.com/questions/20383878/… Il m'a fallu un certain temps pour trouver ce bogue car mon application se bloquait sans aucune trace.
Acapulco
13
Il est difficile de copier l'indicateur nécessaire car il s'agit d'un lien, alors voici celui qui peut facilement être copié. android:noHistory="true"
MirroredFate
137

Vous pouvez utiliser le transfert pour supprimer l'activité précédente de la pile d'activités lors du lancement de la suivante. Il y a un exemple de cela dans l'APIDemos , mais en gros tout ce que vous faites, c'est appeler finish()immédiatement après avoir appelé startActivity().

Dan Lew
la source
1
Salut Daniel, j'ai lu l'exemple, mais cela n'effacera la pile d'historique que par 1 activité, n'est-ce pas? Si ma pile ressemble à A, B et que je lance C, je veux que C soit la nouvelle racine et efface complètement A et B. Dans l'exemple sdk, appeler finish () de B me laisserait une pile de A , C, non? Merci.
Mark
1
Vous pouvez effacer A lorsque vous lancez B et effacer B lorsque vous lancez C; cependant, je suppose que vous ne pourrez pas reculer de B à A si c'est ce que vous désirez. Je vais devoir y réfléchir davantage si c'est un problème.
Dan Lew
3
Mark, pour réaliser ce que vous voulez, vous devez utiliser le drapeau: FLAG_ACTIVITY_CLEAR_TOP. J'espère que ça aide.
Francisco Junior
3
FLAG_ACTIVITY_CLEAR_TOPne fonctionnera pas car C n'est pas déjà dans la pile arrière.
Timmmm
1
@DanielLew Il y a tellement d'exemples dans l'APIDemos. Vous auriez le nom de l'exemple suggéré?
Stephane
52

Oui, jetez un œil à Intent.FLAG_ACTIVITY_NO_HISTORY .

Matthias
la source
46
Notez que cela ne définit aucun historique pour l'activité que vous lancez. Pour ne pas avoir d'historique de l'activité à partir de laquelle je me lance, je l'ai simplement définie android:noHistory="true"dans le manifeste.
georgiecasey
1
Cela fonctionne bien. Utilisez le intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)pour définir ce drapeau.
vovahost
1
@georgiecasey c'est utile lorsque parfois vous voulez le garder dans l'histoire et parfois vous ne le voulez pas dans l'histoire.
Vihaan Verma
24

Ce n'est probablement pas le moyen idéal de le faire. Si quelqu'un a un meilleur moyen, je serai impatient de le mettre en œuvre. Voici comment j'ai accompli cette tâche spécifique avec le sdk pré-version-11.

dans chaque classe que vous souhaitez quitter quand il est temps clair, vous devez le faire:

    ... interesting code stuff ...
    Intent i = new Intent(MyActivityThatNeedsToGo.this, NextActivity.class);
    startActivityForResult(i, 0);
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (resultCode == R.string.unwind_stack_result_id) {
        this.setResult(R.string.unwind_stack_result_id);
        this.finish();
    }
}

alors celui qui doit déclencher la chaîne de pops de la pile doit simplement l'appeler lorsque vous voulez l'initier:

NextActivity.this.setResult(R.string.unwind_stack_result_id);
NextActivity.this.finish();

Ensuite, les activités ne sont pas sur la pile!
N'oubliez pas que vous pouvez démarrer une activité, puis commencer à nettoyer derrière elle, l'exécution ne suit pas un seul thread (l'interface utilisateur).

Travis
la source
Au cas où quelqu'un trouverait cela plus tard, je pensais qu'il pourrait être important de savoir, si vous avez fait pivoter l'écran, Android redémarrera utilement votre application lorsque vous sortirez la dernière activité de la pile. Soyez juste conscient de cela!
Travis
C'est une bonne réponse si vous ne souhaitez supprimer une activité de la pile que sous condition en fonction de ce que l'utilisateur fait dans la prochaine activité +1
theMothaShip
23

Une façon de fonctionner avant l'API 11 consiste à commencer d' ActivityGameMainabord, puis à onCreatedémarrer cette activité dans l' ActivitySplashScreenactivité. Le ActivityGameMainn'apparaîtra pas lorsque vous appelez startActivity trop tôt pour le splash.

Ensuite, vous pouvez effacer la pile au début ActivityGameMainen définissant ces drapeaux sur l'intention:

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

Vous devez également l'ajouter à ActivitySplashScreen:

@Override
public void onBackPressed() {
    moveTaskToBack(true);
}

Donc, le fait de revenir sur cette activité ne vous revient pas ActivityGameMain.

Je suppose que vous ne voulez pas non plus que l'écran de démarrage soit rétabli, pour ce faire, je suggère de le configurer noHistorydans votre AndroidManifest.xml. Mettez ensuite le goBackPressedcode dans votre ActivitySplashScreenSignUpclasse à la place.

Cependant, j'ai trouvé quelques façons de briser cela. Démarrez une autre application à partir d'une notification lorsque ActivitySplashScreenSignUps'affiche et que l'historique de retour n'est pas réinitialisé.

Le seul vrai moyen de contourner cela est dans l'API 11:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
mxcl
la source
20

J'utilise de cette façon.

Intent i = new Intent(MyOldActivity.this, MyNewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);
Smiderle
la source
Merci. J'ai trouvé cela utile dans le cas où il y avait un bouton Accueil dans mon menu, et je ne voulais pas que les activités empilées apparaissent une fois que l'utilisateur a cliqué sur Accueil à partir de là.
ghitesh
8

Je sais que je suis en retard sur ce point (cela fait deux ans que la question a été posée), mais j'ai accompli cela en interceptant la touche de retour. Plutôt que de vérifier des activités spécifiques, je regarde simplement le nombre et s'il est inférieur à 3, il envoie simplement l'application à l'arrière (pause de l'application et retour de l'utilisateur à tout ce qui était en cours d'exécution avant le lancement). J'en vérifie moins de trois car je n'ai qu'un seul écran d'introduction. De plus, je vérifie le nombre car mon application permet à l'utilisateur de revenir à l'écran d'accueil via le menu, ce qui leur permet de sauvegarder à travers d'autres écrans comme d'habitude s'il y a des activités autres que l'écran d'introduction sur la pile.

//We want the home screen to behave like the bottom of the activity stack so we do not return to the initial screen
//unless the application has been killed. Users can toggle the session mode with a menu item at all other times.
@Override
public void onBackPressed() {
    //Check the activity stack and see if it's more than two deep (initial screen and home screen)
    //If it's more than two deep, then let the app proccess the press
    ActivityManager am = (ActivityManager)this.getSystemService(Activity.ACTIVITY_SERVICE);
    List<RunningTaskInfo> tasks = am.getRunningTasks(3); //3 because we have to give it something. This is an arbitrary number
    int activityCount = tasks.get(0).numActivities;

    if (activityCount < 3)
    {
        moveTaskToBack(true);
    }
    else
    {
        super.onBackPressed();
    }
}
alphonzo79
la source
7

Dans le manifeste, vous pouvez ajouter:

android:noHistory="true"

<activity
android:name=".ActivityName"
android:noHistory="true" />

Vous pouvez également appeler

finish()

immédiatement après avoir appelé startActivity (..)

Anubhav
la source
2
Mieux vaut utiliser des indicateurs d'activité que de mettre des choses dans le manifeste.
Trevor Hart
6

Il suffit de définir noHistory="true"dans le fichier manifeste . Cela rend l'activité supprimée du backstack.

Stanislaw Brzezinski
la source
4

C'est fou que personne n'ait mentionné cette solution élégante. Ce devrait être la réponse acceptée.

SplashActivity -> AuthActivity -> DashActivity

if (!sessionManager.isLoggedIn()) {
    Intent intent = new Intent(context, AuthActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
    context.startActivity(intent);
    finish();
} else {
   Intent intent = new Intent(context, DashActivity.class);
   context.startActivity(intent);
    finish();
}

La clé ici est d'utiliser intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); pour l'intermédiaire Activity. Une fois ce lien du milieu rompu, le DashActivitytestament sera le premier et le dernier de la pile.

android:noHistory="true"est une mauvaise solution, car elle pose des problèmes lors de l'utilisation du Activitycomme un rappel par exemple onActivityResult. C'est la solution recommandée et doit être acceptée.

Rowland Mtetezi
la source
1
Ce drapeau semblait trop beau pour être vrai. FLAG_ACTIVITY_NO_HISTORY fonctionne bien et comme on pourrait s'y attendre jusqu'à ce que l'on place l'application en arrière-plan, puis de nouveau au premier plan tout en ayant l'activité avec le drapeau au-dessus de la pile. En allant en arrière-plan, l'activité est détruite. En revenant à l'application, on verra l'activité précédente de la pile. Je ne voulais définitivement pas un tel comportement.
NeverwinterMoon
4

C'est trop tard mais j'espère que ça aide. La plupart des réponses ne pointent pas dans la bonne direction. Il y a deux drapeaux simples pour une telle chose.

intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);

Depuis les documents Android:

public static final int FLAG_ACTIVITY_CLEAR_TASK Ajouté dans l'API niveau 11

If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the

activité à effacer avant le début de l'activité. En d'autres termes, l'activité devient la nouvelle racine d'une tâche autrement vide et toutes les anciennes activités sont terminées. Cela ne peut être utilisé qu'en conjonction avec FLAG_ACTIVITY_NEW_TASK.

Nouman Ghaffar
la source
1

Appelez simplement this.finish () avant startActivity (intention) comme ceci-

       Intent intent = new Intent(ActivityOne.this, ActivityTwo.class);
        this.finish();
        startActivity(intent);

la source
les utilisateurs qui ont une erreur sur "ceci", devraient la changer en "ActivityOne.this"
ninbit
1

La suppression d'une activité d'un historique se fait en mettant le drapeau avant l'activité Vous ne voulez pas

A-> B-> C-> D

Supposons que A, B, C et D sont 4 activités si vous souhaitez effacer B et C, puis définissez l'indicateur

intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

Dans l'activité A et B

Voici le bit de code

Intent intent = new Intent(this,Activity_B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
branlant
la source
0
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            super.finishAndRemoveTask();
        }
        else {
            super.finish();
        }
impatient
la source
-7

Essaye ça:

intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)

c'est le niveau API 1, vérifiez le lien .

Alécio Carvalho
la source
2
Qu'est-ce que c'est censé faire? Ne résout certainement pas le problème en question.
rodrigo-silveira
Êtes-vous sûr de ne pas vouloir dire Intent.FLAG_ACTIVITY_NO_HISTORY?
Riot Goes Woof