374 votes

Effacer toute la pile d'historique et commencer une nouvelle activité sur Android

Est-il possible de démarrer une activité sur la pile, en effaçant tout l'historique avant elle ?

La situation

J'ai une pile d'activités qui va soit A->B->C soit B->C (l'écran A sélectionne le jeton de l'utilisateur, mais de nombreux utilisateurs n'ont qu'un seul jeton).

Dans l'écran C, l'utilisateur puede prennent une action qui rend l'écran B invalide, l'application veut donc les amener à l'écran A, qu'il soit ou non déjà dans la pile. L'écran A devrait alors être le seul élément de la pile dans mon application.

Notes

Il existe de nombreuses autres questions similaires, mais je n'ai rien trouvé qui réponde à cette question exacte. J'ai essayé d'appeler getParent().finish() - cela donne toujours lieu à une exception de pointeur nul. FLAG_ACTIVITY_CLEAR_TOP ne fonctionne que si l'activité est déjà sur la pile.

731voto

Akos Cz Points 3880

Dans le niveau 11 de l'API, un nouvel indicateur d'intention a été ajouté à cet effet : Intent.FLAG_ACTIVITY_CLEAR_TASK (en anglais)

Juste pour clarifier, utilisez ceci :

Java

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

Kotlin

intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK

Malheureusement pour les API lvl <= 10, je n'ai pas encore trouvé de solution propre à ce problème. Le site La solution "DontHackAndroidLikeThis". est en effet une pure piraterie. Vous ne devriez pas faire ça. :)

Edit : Selon @ Ben Pearson Pour l'API <=10, on peut maintenant utiliser la fonction IntentCompat pour la même chose. On peut utiliser IntentCompat.FLAG_ACTIVITY_CLEAR_TASK pour effacer la tâche. Vous pouvez donc également prendre en charge le niveau 11 de l'API.

26 votes

Pour clarifier, utilisez ceci : intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) ;

2 votes

Sans l'Intent.FLAG_ACTIVITY_NEW_TASK l'application se ferme parfois toute seule sur Android 4

22 votes

IntentCompat dispose également d'un drapeau permettant d'effacer la tâche, ce qui vous permet de prendre en charge des tâches antérieures au niveau 11 de l'API. developer.Android.com/reference/Android/support/v4/content/

55voto

monish george Points 128

Cas 1 : Seulement deux activités A et B :

Ici, le flux de l'activité est A->B. En cliquant sur le bouton de retour de B, nous devons fermer l'application, puis en démarrant l'activité B à partir de A, il suffit d'appeler finish(), ce qui empêchera Android de stocker l'activité A dans le Backstack, par exemple, l'activité A est l'hébergement/écran flash de l'application.

Intent newIntent = new Intent(A.this, B.class);
startActivity(newIntent);
finish();

Cas 2 : Plus de deux activités :

S'il y a un flux tel que A->B->C->D->B et que l'on clique sur le bouton de retour dans l'activité B alors que l'on vient de l'activité D. Dans ce cas, nous devrions utiliser le bouton de retour.

Intent newIntent = new Intent(D.this,B.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(newIntent);

Ici, l'activité B sera lancée à partir de la pile arrière plutôt qu'à partir d'une nouvelle instance en raison de Intent.FLAG_ACTIVITY_CLEAR_TOP et Intent.FLAG_ACTIVITY_NEW_TASK qui effacent la pile et la placent au sommet de celle-ci.

2 votes

Ça a marché pour moi. J'ai mis ces drapeaux dans TOUTES les activités. Dans ces activités, les boutons de retour fonctionnent parfaitement pour aller à l'activité précédente, et dans l'activité principale avec Intent intent = new Intent(Intent.ACTION_MAIN) ; intent.addCategory(Intent.CATEGORY_HOME) ; intent.addFlags(Intent. FLAG_ACTIVITY_CLEAR_TOP) ; intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) ; startActivity(intent) ; finish() ; Toute l'application est fermée, elle est toujours en mémoire mais n'est pas active, et si vous redémarrez l'application, elle revient à l'écran d'accueil :)

0 votes

Cela devrait être la meilleure réponse. Si quelqu'un a un scénario identique au mien : A->B->C->D->E->(B) De E->B devrait avoir un résultat : A->B

26voto

user2895402 Points 31

J'ai aussi passé quelques heures sur ce sujet... et je suis d'accord pour dire que FLAG_ACTIVITY_CLEAR_TOP ressemble à ce que vous voulez : effacer toute la pile, sauf l'activité en cours de lancement, de sorte que le bouton Back quitte l'application. Cependant, comme Mike Repass l'a mentionné, FLAG_ACTIVITY_CLEAR_TOP ne fonctionne que lorsque l'activité que vous lancez est déjà dans la pile ; lorsque l'activité n'est pas là, l'indicateur ne fait rien.

Que faire ? Placez l'activité en cours de lancement dans la pile avec FLAG_ACTIVITY_NEW_TASK, qui fait de cette activité le début d'une nouvelle tâche sur la pile de l'historique. Ensuite, ajoutez le drapeau FLAG_ACTIVITY_CLEAR_TOP.

Maintenant, quand FLAG_ACTIVITY_CLEAR_TOP va chercher la nouvelle activité dans la pile, elle sera là et sera tirée vers le haut avant que tout le reste soit effacé.

Voici ma fonction de déconnexion ; le paramètre View est le bouton auquel la fonction est attachée.

public void onLogoutClick(final View view) {
    Intent i = new Intent(this, Splash.class);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    startActivity(i);
    finish();
}

1 votes

Voulez-vous dire CLEAR_TASK au lieu de CLEAR_TOP ?

13voto

Keith Maurino Points 1245

Immédiatement après le début d'une nouvelle activité, en utilisant la fonction startActivity assurez-vous d'appeler finish() afin que l'activité en cours ne soit pas empilée derrière la nouvelle.

0 votes

+1 Belle solution pour empêcher qu'une seule activité dans une certaine situation soit mise sur la pile de l'historique.

29 votes

Ne fonctionne pas si vous avez plus d'une activité dans la pile, la fin efface juste l'activité précédente mais pas les autres....

12voto

Macarse Points 36519

Vous ne devriez pas changer la pile. Le bouton retour d'Android doit fonctionner comme dans un navigateur web.

Je peux penser à un moyen de le faire, mais c'est une sacrée pirouette.

  • Faites vos activités singleTask en l'ajoutant à la AndroidManifest Exemple :

    <activity android:name=".activities.A"
              android:label="@string/A_title"
              android:launchMode="singleTask"/>
    
    <activity android:name=".activities.B"
              android:label="@string/B_title"
              android:launchMode="singleTask"/>
  • Étendre le site Application qui contiendra la logique de l'endroit où aller.

Exemple :

public class DontHackAndroidLikeThis extends Application {

  private Stack<Activity> classes = new Stack<Activity>();

  public Activity getBackActivity() {
    return classes.pop();
  }

  public void addBackActivity(Activity activity) {
    classes.push(activity);
  }
}

De A à B :

DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(A.class); 
startActivity(this, B.class);

De B à C :

DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
app.addBackActivity(B.class); 
startActivity(this, C.class);

En C :

If ( shouldNotGoBackToB() ) {
  DontHackAndroidLikeThis app = (DontHackAndroidLikeThis) getApplication();
  app.pop();
}

et de gérer le bouton retour à pop() de la pile.

Encore une fois, vous ne devriez pas faire ça :)

1 votes

Finalement, j'ai décidé de laisser la pile intacte et de dire à l'utilisateur que son écran actuel n'était pas valide.

1 votes

Très frustrant qu'Android ne nous permette pas déjà de gérer la pile d'activité de cette façon. Je serais tenté d'utiliser cette solution dans mes futures applications Android.

4 votes

Pour être clair sur la raison pour laquelle il ne faut pas l'utiliser : c'est un bon moyen de créer des fuites de mémoire. À un moment donné, le système d'exploitation peut décider de mettre fin aux activités d'arrière-plan, mais puisque Application Dans ce cas, le système d'exploitation ne sera pas en mesure de libérer la mémoire vive laissée par les activités détruites.

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