Entfernen einer Aktivität aus dem Verlaufsstapel

382

Meine App zeigt eine Anmeldeaktivität an, wenn der Benutzer die App zum ersten Mal ausführt.

  1. ActivitySplashScreen (Willkommen im Spiel, Konto eröffnen?)
  2. ActivitySplashScreenSignUp (großartig, füllen Sie diese Informationen aus)
  3. ActivityGameMain (Hauptspielbildschirm)

Die Aktivitäten starten sich also genau in dieser Reihenfolge, wenn der Benutzer auf jedem Bildschirm durch eine Schaltfläche klickt.

Wenn der Benutzer von Aktivität 2 zu 3 wechselt, ist es dann möglich, 1 und 2 vollständig vom Verlaufsstapel zu löschen? Ich möchte, dass der Benutzer, wenn er sich auf # 3 befindet und auf die Schaltfläche "Zurück" drückt, einfach zum Startbildschirm und nicht zum Begrüßungsbildschirm zurückkehrt.

Ich denke, ich kann dies mit Aufgaben erreichen (dh eine neue Aufgabe auf # 3 starten), wollte aber sehen, ob es eine einfachere Methode gibt.

Vielen Dank

Kennzeichen
quelle
Wenn der Benutzer Ihre App auf dem Startbildschirm wieder aufnimmt, wird er dann zu ActivitySplashScreen oder ActivityGameMain weitergeleitet?
Tamil

Antworten:

632

Sie können dies erreichen , indem die Einstellung android:noHistory Attribut zu "true"in den entsprechenden <activity>Einträgen in der AndroidManifest.xmlDatei. Zum Beispiel:

<activity
    android:name=".AnyActivity"
    android:noHistory="true" />
Aitor Gómez
quelle
12
Dies ist der beste Weg, dies zu tun.
Shkschneider
22
Gleichermaßen können Sie verwenden FLAG_ACTIVITY_NO_HISTORY.
Timmmm
34
Wie kann ich dies aus Code erreichen? Weil ich das nicht die ganze Zeit machen will. Ich möchte eine bestimmte Aktivität nur unter bestimmten Bedingungen aus der Geschichte entfernen.
Namratha
8
Beachten Sie jedoch, dass durch die Verwendung des Attributs noHistory diese Aktivität beendet wird, was beispielsweise bei der G + -Anmeldung zu unerwartetem Verhalten führen kann. Siehe: stackoverflow.com/questions/20383878/… Ich habe eine Weile gebraucht , um diesen Fehler zu finden, da meine App spurlos abstürzte.
Acapulco
13
Es ist schwierig, das benötigte Flag zu kopieren, da es sich um einen Link handelt, also hier einen, der leicht kopiert werden kann. android:noHistory="true"
MirroredFate
137

Mit der Weiterleitung können Sie die vorherige Aktivität aus dem Aktivitätsstapel entfernen, während Sie die nächste starten. Es gibt ein Beispiel dafür in den APIDemos , aber im Grunde rufen Sie nur finish()sofort nach dem Anruf an startActivity().

Dan Lew
quelle
1
Hallo Daniel, ich habe das Beispiel durchgelesen, aber das löscht den Verlaufsstapel nur um 1 Aktivität, nicht wahr? Wenn mein Stapel wie A, B aussieht und ich C starte, möchte ich, dass C die neue Wurzel ist und A und B vollständig löscht. Im SDK-Beispiel würde das Aufrufen von finish () von B einen Stapel von A hinterlassen C, nicht wahr? Vielen Dank.
Mark
1
Sie können A löschen, während Sie B starten, und B löschen, wenn Sie C starten. Ich nehme jedoch an, dass Sie dann nicht von B nach A zurückkehren können, wenn Sie dies wünschen. Ich muss mehr darüber nachdenken, wenn das ein Problem ist.
Dan Lew
3
Markieren Sie, um das zu erreichen, was Sie wollen, müssen Sie das Flag FLAG_ACTIVITY_CLEAR_TOP verwenden. Ich hoffe, es hilft.
Francisco Junior
3
FLAG_ACTIVITY_CLEAR_TOPfunktioniert nicht, da C nicht bereits im Backstack enthalten ist.
Timmmm
1
@ DanielLew Es gibt so viele Beispiele in den APIDemos. Sie hätten den Namen des vorgeschlagenen Beispiels?
Stephane
52

Ja, schauen Sie sich Intent.FLAG_ACTIVITY_NO_HISTORY an .

Matthias
quelle
46
Beachten Sie, dass hierdurch kein Verlauf für die Aktivität festgelegt wird, für die Sie starten. Um keinen Verlauf für die Aktivität zu haben, von der aus Sie starten, habe ich ihn einfach android:noHistory="true"im Manifest festgelegt.
Georgiecasey
1
Das funktioniert gut. Verwenden Sie das intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY), um dieses Flag zu setzen.
Vovahost
1
@georgiecasey Dies ist nützlich, wenn Sie es manchmal in der Geschichte behalten möchten und manchmal nicht in der Geschichte.
Vihaan Verma
24

Dies ist wahrscheinlich nicht der ideale Weg, dies zu tun. Wenn jemand einen besseren Weg hat, freue ich mich darauf, ihn umzusetzen. Hier ist, wie ich diese spezielle Aufgabe mit SDK vor Version 11 erledigt habe.

In jeder Klasse, die Sie verlassen möchten, wenn es klar ist, müssen Sie Folgendes tun:

    ... 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();
    }
}

dann muss derjenige, der die Pop-Kette vom Stapel abheben muss, dies einfach aufrufen, wenn Sie es initiieren möchten:

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

Dann sind die Aktivitäten nicht auf dem Stapel!
Denken Sie daran, Leute, dass Sie eine Aktivität starten und dann dahinter aufräumen können. Die Ausführung folgt keinem einzelnen (der UI) Thread.

Travis
quelle
Für den Fall, dass jemand später darauf stößt, dachte ich, es könnte sich als wichtig erweisen, zu wissen, ob Sie den Bildschirm gedreht haben. Android wird Ihre Anwendung hilfreich für Sie neu starten, wenn Sie die letzte Aktivität vom Stapel nehmen. Sei dir dessen einfach bewusst!
Travis
Dies ist eine gute Antwort, wenn Sie eine Aktivität nur bedingt vom Stapel entfernen möchten, je nachdem, was der Benutzer in der nächsten Aktivität +1
theMothaShip
23

Eine Möglichkeit, die vor API 11 funktioniert, besteht darin, ActivityGameMainzuerst zu starten und dann in onCreatedieser Aktivität Ihre ActivitySplashScreenAktivität zu starten . Das ActivityGameMainwird nicht angezeigt, wenn Sie startActivity zu früh für den Splash aufrufen.

Dann Sie können den Stapel löschen beim Start ActivityGameMaindurch das Setzen diesen Flags auf dem Intent:

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

Sie müssen dies auch zu ActivitySplashScreen hinzufügen:

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

Das Zurückdrücken dieser Aktivität geht also nicht auf Ihre zurück ActivityGameMain.

Ich gehe davon aus, dass Sie nicht möchten, dass der Begrüßungsbildschirm wieder angezeigt wird. Um dies zu erreichen, schlage ich vor, ihn noHistoryin Ihrem Bildschirm einzustellen AndroidManifest.xml. Fügen goBackPressedSie dann ActivitySplashScreenSignUpstattdessen den Code in Ihre Klasse ein.

Ich habe jedoch einige Möglichkeiten gefunden, dies zu brechen. Starten Sie eine andere App von einer Benachrichtigung aus, während diese ActivitySplashScreenSignUpangezeigt wird und der Hintergrund nicht zurückgesetzt wird.

Der einzige wirkliche Weg, dies zu umgehen, ist in API 11:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
mxcl
quelle
20

Ich benutze diesen Weg.

Intent i = new Intent(MyOldActivity.this, MyNewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);
Smiderle
quelle
Vielen Dank. Ich fand dies hilfreich für den Fall, dass sich in meinem Menü eine Home-Schaltfläche befand und ich nicht wollte, dass gestapelte Aktivitäten angezeigt werden, sobald der Benutzer von dort aus nach Hause geklickt hat.
Ghitesh
8

Ich weiß, dass ich zu spät dran bin (es ist zwei Jahre her, seit die Frage gestellt wurde), aber ich habe dies erreicht, indem ich den Druck auf die Zurück-Taste abgefangen habe. Anstatt nach bestimmten Aktivitäten zu suchen, schaue ich mir nur die Anzahl an und wenn es weniger als 3 ist, schickt es die App einfach nach hinten (pausiert die App und bringt den Benutzer zu dem zurück, was vor dem Start ausgeführt wurde). Ich suche nach weniger als drei, weil ich nur einen Intro-Bildschirm habe. Außerdem überprüfe ich die Anzahl, da der Benutzer mit meiner App über das Menü zum Startbildschirm zurückkehren kann, sodass er wie gewohnt über andere Bildschirme sichern kann, wenn andere Aktivitäten als der Intro-Bildschirm auf dem Stapel vorhanden sind.

//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
quelle
7

Im Manifest können Sie hinzufügen:

android:noHistory="true"

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

Sie können auch anrufen

finish()

unmittelbar nach dem Aufruf von startActivity (..)

Anubhav
quelle
2
Verwenden Sie lieber Aktivitätsflags, als Dinge in das Manifest zu setzen.
Trevor Hart
6

Einfach noHistory="true"in Manifest- Datei einstellen . Dadurch wird die Aktivität aus dem Backstack entfernt.

Stanislaw Brzezinski
quelle
4

Es ist verrückt, dass niemand diese elegante Lösung erwähnt hat. Dies sollte die akzeptierte Antwort sein.

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();
}

Der Schlüssel hier ist intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); für den Vermittler zu verwenden Activity. Sobald diese mittlere Verbindung unterbrochen ist, DashActivitywird der erste und letzte im Stapel.

android:noHistory="true"ist eine schlechte Lösung, da es Probleme verursacht, wenn man sich auf das Activityals Rückruf verlässt, z onActivityResult. Dies ist die empfohlene Lösung und sollte akzeptiert werden.

Rowland Mtetezi
quelle
1
Diese Flagge klang zu gut um wahr zu sein. FLAG_ACTIVITY_NO_HISTORY funktioniert gut und wie zu erwarten, bis die App in den Hintergrund und dann wieder in den Vordergrund gestellt wird, während die Aktivität mit dem Flag oben auf dem Stapel ausgeführt wird. Wenn Sie in den Hintergrund gehen, wird die Aktivität zerstört. Wenn Sie zur App zurückkehren, wird die vorherige Aktivität vom Stapel angezeigt. Ich wollte ein solches Verhalten definitiv nicht.
NeverwinterMoon
4

Es ist zu spät, aber ich hoffe, es hilft. Die meisten Antworten zeigen nicht in die richtige Richtung. Es gibt zwei einfache Flaggen für so etwas.

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

Aus Android-Dokumenten:

public static final int FLAG_ACTIVITY_CLEAR_TASK In API-Ebene 11 hinzugefügt

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

Aktivität, die gelöscht werden muss, bevor die Aktivität gestartet wird. Das heißt, die Aktivität wird zur neuen Wurzel einer ansonsten leeren Aufgabe, und alle alten Aktivitäten werden beendet. Dies kann nur in Verbindung mit FLAG_ACTIVITY_NEW_TASK verwendet werden.

Nouman Ghaffar
quelle
1

Rufen Sie einfach this.finish () auf, bevor Sie startActivity (intent) wie folgt starten:

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

quelle
Benutzer, die Fehler bei "this" haben, sollten ihn in "ActivityOne.this"
ändern
1

Das Entfernen einer Aktivität aus einem Verlauf erfolgt durch Setzen des Flags vor der Aktivität, die Sie nicht möchten

A-> B-> C-> D.

Angenommen, A, B, C und D sind 4 Aktivitäten, wenn Sie B und C löschen möchten, und setzen Sie dann das Flag

intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

In der Aktivität A und B.

Hier ist das Codebit

Intent intent = new Intent(this,Activity_B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
wackelig
quelle
0
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            super.finishAndRemoveTask();
        }
        else {
            super.finish();
        }
eifriger Prinz
quelle
-7

Versuche dies:

intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)

Es ist API Level 1, überprüfen Sie den Link .

Alécio Carvalho
quelle
2
Was soll das machen? Löst das fragliche Problem definitiv nicht.
Rodrigo-Silveira
Bist du sicher, dass du es nicht so gemeint hast Intent.FLAG_ACTIVITY_NO_HISTORY?
Riot Goes Woof