Löschen Sie den gesamten Verlaufsstapel und starten Sie eine neue Aktivität unter Android

332

Ist es möglich, eine Aktivität auf dem Stapel zu starten und den gesamten Verlauf davor zu löschen?

Die Situation

Ich habe einen Aktivitätsstapel, der entweder A-> B-> C oder B-> C lautet (Bildschirm A wählt das Benutzertoken aus, aber viele Benutzer haben nur ein einziges Token).

Im Bildschirm C der Benutzer kann eine Aktion , den Bildschirm B ungültig macht, so dass die Anwendung sie auf Bildschirm A nehmen will, und zwar unabhängig davon , ob es bereits in dem Stapel. Bildschirm A sollte dann das einzige Element auf dem Stapel in meiner Anwendung sein.

Anmerkungen

Es gibt viele andere ähnliche Fragen, aber ich habe nichts gefunden, was genau diese Frage beantwortet. Ich habe versucht anzurufen getParent().finish()- dies führt immer zu einer Nullzeigerausnahme. FLAG_ACTIVITY_CLEAR_TOPFunktioniert nur, wenn sich die Aktivität bereits auf dem Stapel befindet.

Casebash
quelle

Antworten:

658

In API Level 11 wurde nur dafür ein neues Intent Flag hinzugefügt: Intent.FLAG_ACTIVITY_CLEAR_TASK

Verwenden Sie zur Verdeutlichung Folgendes:

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


Leider habe ich für API lvl <= 10 noch keine saubere Lösung dafür gefunden. Die "DontHackAndroidLikeThis" -Lösung ist in der Tat reine Hackerei. Das solltest du nicht tun. :) :)

Bearbeiten: Gemäß dem Kommentar von @ Ben Pearson kann für API <= 10 jetzt die IntentCompat- Klasse für dieselbe verwendet werden. Man kann IntentCompat.FLAG_ACTIVITY_CLEAR_TASKFlag verwenden, um die Aufgabe zu löschen. Sie können also auch Pre-API-Level 11 unterstützen.

Akos Cz
quelle
23
Verwenden Sie zur Verdeutlichung Folgendes: intent.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
user123321
2
ohne die Intent.FLAG_ACTIVITY_NEW_TASK schließt sich die App manchmal einfach auf Android 4
max4ever
22
IntentCompat hat jetzt auch ein Flag zum Löschen von Aufgaben, sodass Sie Pre-API-Level 11 unterstützen können - developer.android.com/reference/android/support/v4/content/…
Ben Pearson
10
IntentCompat.FLAG_ACTIVITY_CLEAR_TASK wird auf Geräten mit API-Level <10 ignoriert. Developer.android.com/reference/android/support/v4/content/…
David
7
Das Flag von IntentCompat dient nur dazu, einen Absturz zu vermeiden, unternimmt jedoch nichts, wie @David sagt.
Sloy
49

Fall 1: Nur zwei Aktivitäten A und B:

Hier ist der Aktivitätsfluss A-> B. Wenn Sie auf die Schaltfläche "Zurück" von B klicken, müssen Sie die Anwendung schließen. Wenn Sie dann die Aktivität B von A aus starten, rufen Sie einfach finish () auf. Dadurch wird verhindert, dass Android die Aktivität A im Backstack.eg für Aktivität A speichert Loding / Splash-Bildschirm der Anwendung.

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

Fall 2: Mehr als zwei Aktivitäten:

Wenn es einen Fluss wie A-> B-> C-> D-> B gibt und Sie in Aktivität B auf die Schaltfläche Zurück klicken, während Sie von Aktivität D kommen. In diesem Fall sollten wir verwenden.

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

Hier wird Aktivität B aufgrund von Intent.FLAG_ACTIVITY_CLEAR_TOP und Intent.FLAG_ACTIVITY_NEW_TASK vom Backstack aus gestartet und nicht von einer neuen Instanz. Dadurch wird der Stapel gelöscht und zum obersten. Wenn wir also die Zurück-Taste drücken, wird die gesamte Anwendung beendet.

Monish George
quelle
2
Das hat bei mir funktioniert. Ich habe in ALLE Aktivitäten diese Flaggen gesetzt. In diesen Aktivitäten funktionieren die Zurück-Schaltflächen perfekt zur vorherigen Aktivität und in der Hauptaktivität mit Absichtsabsicht = neue Absicht (Intent.ACTION_MAIN); intent.addCategory (Intent.CATEGORY_HOME); intent.addFlags (Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags (Intent.FLAG_ACTIVITY_NEW_TASK); startActivity (Absicht); Fertig(); Die ganze App ist geschlossen, noch im Speicher, aber nicht aktiv, und wenn Sie neu starten, geht die App zum Begrüßungsbildschirm :)
Rako
Dies sollte die beste Antwort sein. Wenn jemand das gleiche Szenario mit mir hat: A-> B-> C-> D-> E -> (B) Von E-> B sollte ein Ergebnis haben: A-> B
Shem Alexis Chavez
39

Mit der neueren Version von Android> = API 16 verwenden finishAffinity()

Ansatz ist geeignet für> = API 16.

Intent mIntent = new Intent(mContext,MainActivity.class);
finishAffinity();
startActivity(mIntent);
  • Dies entspricht dem Starten einer neuen Aktivität und dem Löschen des gesamten Stapels.
  • ODER Starten Sie MainActivity / FirstActivity neu.
Karan
quelle
1
Das hat den Trick gemacht, die Flags haben bei 4.xx nicht für mich funktioniert und das hat perfekt funktioniert! Vielen Dank
Jonathan Aste
1
Dies scheint die richtige Antwort zu sein, wenn Ihr Ziel darin besteht, alle unten aufgeführten Aktivitäten einschließlich der aktuellen Aktivität abzuschließen und eine neue Aktivität in ihrer eigenen Aufgabe zu starten.
ToBe
24

Ich habe auch ein paar Stunden damit verbracht ... und bin damit einverstanden, dass FLAG_ACTIVITY_CLEAR_TOP so klingt, wie Sie es möchten: Löschen Sie den gesamten Stapel, mit Ausnahme der Aktivität, die gestartet wird, sodass die Schaltfläche Zurück die Anwendung beendet. Wie Mike Repass bereits erwähnt hat, funktioniert FLAG_ACTIVITY_CLEAR_TOP nur, wenn sich die Aktivität, die Sie starten, bereits im Stapel befindet. Wenn die Aktivität nicht vorhanden ist, führt die Flagge nichts aus.

Was ist zu tun? Fügen Sie die zu startende Aktivität mit FLAG_ACTIVITY_NEW_TASK in den Stapel ein. Dadurch wird diese Aktivität zum Start einer neuen Aufgabe im Verlaufsstapel. Fügen Sie dann das Flag FLAG_ACTIVITY_CLEAR_TOP hinzu.

Wenn FLAG_ACTIVITY_CLEAR_TOP die neue Aktivität im Stapel findet, wird sie dort angezeigt und aufgerufen, bevor alles andere gelöscht wird.

Hier ist meine Abmeldefunktion. Der Parameter Ansicht ist die Schaltfläche, an die die Funktion angehängt ist.

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();
}
user2895402
quelle
1
meinst du CLEAR_TASK statt CLEAR_TOP?
Andy
14

Sie sollten den Stapel nicht ändern. Die Android-Zurück-Schaltfläche sollte wie in einem Webbrowser funktionieren.

Ich kann mir einen Weg vorstellen, es zu tun, aber es ist ein ziemlicher Hack.

  • Machen Sie Ihre Aktivitäten, singleTaskindem Sie sie dem AndroidManifest Beispiel hinzufügen :

    <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"/>
  • Erweitern Sie Application, um die Logik des Ziels festzulegen .

Beispiel:

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

Von A nach B:

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

Von B nach C:

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

In C:

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

und betätigen Sie den Zurück-Knopf pop()vom Stapel.

Noch einmal, du solltest das nicht tun :)

Macarse
quelle
Am Ende entscheide ich mich, den Stapel intakt zu lassen und dem Benutzer nur mitzuteilen, dass sein aktueller Bildschirm ungültig war
Casebash
1
Sehr frustrierend, dass wir mit Android den Aktivitätsstapel nicht schon so verwalten können. Ich wäre versucht, diese Lösung in meinen zukünftigen Android-Apps zu verwenden.
Cephron
4
Nur um klar zu sein, warum dies nicht verwendet werden sollte: Es ist eine gute Möglichkeit, Speicherlecks zu erstellen. Irgendwann kann das Betriebssystem entscheiden, Hintergrundaktivitäten zu beenden, aber da es Applicationihre Instanzen benötigt, kann das Betriebssystem den verbleibenden RAM nicht mehr von den zerstörten Aktivitäten freigeben.
Vit Khudenko
@Arhimed Gibt es noch andere Probleme? Der Speicherverlust kann behoben werden, indem nur schwache Referenzen beibehalten werden.
Navin
1
@Navin Ja, Lecks können mit schwachen Refs vermieden werden, aber wenn es nach GC keine Live-Aktivitätsreferenz gibt, ist der gesamte Ansatz nutzlos. Noch einmal - tun Sie dies nicht, dies ist ein falscher Ansatz für Android.
Vit Khudenko
12

Stellen Sie unmittelbar nach dem Starten einer neuen Aktivität mit startActivitysicher, dass Sie aufrufen, finish()damit die aktuelle Aktivität nicht hinter der neuen gestapelt wird.

Keith Maurino
quelle
+1 Gute Lösung, um zu verhindern, dass genau eine Aktivität in einer bestimmten Situation auf den Verlaufsstapel gelegt wird.
Marsbear
27
funktioniert nicht, wenn Sie mehr als eine Aktivität im Stapel haben. Das Ziel
löscht
5

Versuche dies:

Intent logout_intent = new Intent(DashboardActivity.this, LoginActivity.class);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
logout_intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(logout_intent);
finish();
Mohammad
quelle
4

Erweitertes wiederverwendbares Kotlin:

Sie können das Flag direkt mit der Setter-Methode setzen. In Kotlin orist der Ersatz für Java bitweise oder |.

intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK

Wenn Sie dies regelmäßig verwenden möchten, erstellen Sie eine Absichtserweiterungsfunktion

fun Intent.clearStack() {
    flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}

Sie können diese Funktion dann direkt aufrufen, bevor Sie die Absicht starten

intent.clearStack()

Wenn Sie in anderen Situationen die Option zum Hinzufügen zusätzlicher Flags benötigen, fügen Sie der Erweiterungsfunktion einen optionalen Parameter hinzu.

fun Intent.clearStack(additionalFlags: Int = 0) {
    flags = additionalFlags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
Gibolt
quelle
2
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
Neeraj Gupta
quelle
2

Versuchen Sie unten Code,

Intent intent = new Intent(ManageProfileActivity.this, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
                Intent.FLAG_ACTIVITY_CLEAR_TASK| 
                Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
Shashikant Yadav
quelle
wenn Uhr wie diese mit activityis erneut Aufruf api aktualisiert , aber vorher vorhandene alle statck gelöscht
Harsha
2

Bei mir funktioniert keine der oben genannten Methoden .

Tun Sie dies einfach, um alle vorherigen Aktivitäten zu löschen :

finishAffinity() // if you are in fragment use activity.finishAffinity()
Intent intent = new Intent(this, DestActivity.class); // with all flags you want
startActivity(intent)
Amir Hossein Ghasemi
quelle
-1

Manchmal kann es sein, dass Ihr Android-Emulator keine Verbindung zum Eclipse-DDMS-Tool herstellt und adb auffordert, manuell zu starten. In diesem Fall können Sie die ADB über die Eingabeaufforderung starten oder stoppen.

RajeshkumarG
quelle
1
Manchmal kann es sein, dass Ihr Android-Emulator keine Verbindung zum Eclipse-DDMS-Tool herstellt und adb auffordert, manuell zu starten. In diesem Fall können Sie die ADB über die Eingabeaufforderung starten oder stoppen. Absicht i = neue Absicht (OldActivity.this, NewActivity.class); // setze die neue Aufgabe und lösche Flags i.setFlags (Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) startActivity (i);
RajeshkumarG
-2

Ich fand zu einfachen Hack einfach dies hinzufügen neues Element hinzufügen AndroidManifestals: -

<activity android:name=".activityName"
          android:label="@string/app_name"
          android:noHistory="true"/>

die android:noHistoryIhre unerwünschte Aktivität von Stapel löschen.

Tauseef
quelle
2
Dieser Ansatz kann unter Android 6.0+ zu Problemen führen, wenn Sie in dieser Aktivität nach Berechtigungen fragen.
Vitaliy A