Usuwanie działania ze stosu historii

382

Moja aplikacja pokazuje rejestrację po pierwszym uruchomieniu aplikacji, wygląda następująco:

  1. ActivitySplashScreen (witaj w grze, założyć konto?)
  2. ActivitySplashScreenSignUp (świetnie, wypełnij te informacje)
  3. ActivityGameMain (główny ekran gry)

więc działania uruchamiają się w dokładnie takiej kolejności, kiedy użytkownik kliknie przycisk na każdym ekranie.

Kiedy użytkownik przechodzi z czynności nr 2 do nr 3, czy można całkowicie wyczyścić stos 1 i 2 z historii? Chciałbym, aby jeśli użytkownik był na # 3 i nacisnął przycisk Wstecz, po prostu poszedł do ekranu głównego, zamiast z powrotem do ekranu powitalnego.

Myślę, że mogę to zrobić za pomocą zadań (tj. Rozpocząć nowe zadanie na nr 3), ale chciałem sprawdzić, czy istnieje prostsza metoda,

Dzięki

znak
źródło
Czy po wznowieniu działania aplikacji na ekranie głównym zabiera go ona do ActivitySplashScreen lub ActivityGameMain?
Tamil

Odpowiedzi:

632

Można to osiągnąć przez ustawienie android:noHistory atrybutu aby "true"w odpowiednich <activity>wpisów w AndroidManifest.xmlpliku. Na przykład:

<activity
    android:name=".AnyActivity"
    android:noHistory="true" />
Aitor Gómez
źródło
12
To najlepszy sposób, aby to zrobić.
shkschneider
22
Odpowiednio możesz użyć FLAG_ACTIVITY_NO_HISTORY.
Timmmm
34
Jak mogę to osiągnąć z kodu? Ponieważ nie chcę tego robić cały czas. Chciałbym usunąć dane działanie z historii tylko pod pewnymi warunkami.
Namratha
8
Pamiętaj tylko, że użycie atrybutu noHistory zakończy działanie, co może spowodować nieoczekiwane zachowanie, na przykład przy logowaniu G +. Zobacz: stackoverflow.com/questions/20383878/… Zajęło mi trochę czasu, aby znaleźć ten błąd, ponieważ moja aplikacja ulegała awarii bez żadnych śladów.
Acapulco,
13
Skopiowanie potrzebnej flagi jest trudne, ponieważ jest to link, więc tutaj można go łatwo skopiować. android:noHistory="true"
MirroredFate
137

Możesz użyć przekazywania, aby usunąć poprzednią aktywność ze stosu aktywności podczas uruchamiania następnej. Przykład tego znajduje się w APIDemos , ale w zasadzie wszystko, co robisz, to dzwonienie finish()natychmiast po wywołaniu startActivity().

Dan Lew
źródło
1
Cześć Daniel, przeczytałem przykład, ale to wyczyści stos historii tylko o 1 aktywność, prawda? Jeśli mój stos wygląda jak A, B i uruchamiam C, chcę, aby C był nowym rootem i całkowicie wyczyścił A i B. W przykładzie sdk, wywołanie finish () z B dałoby mi stos A , C, prawda? Dzięki.
Mark
1
Możesz wyczyścić A podczas uruchamiania B i wyczyścić B podczas uruchamiania C; jednak przypuszczam, że nie byłbyś w stanie wycofać się z B do A, jeśli tego chcesz. Muszę się nad tym zastanowić, jeśli to jest problem.
Dan Lew,
3
Zaznacz, aby osiągnąć to, czego chcesz, musisz użyć flagi: FLAG_ACTIVITY_CLEAR_TOP. Mam nadzieję, że to pomoże.
Francisco Junior
3
FLAG_ACTIVITY_CLEAR_TOPnie będzie działać, ponieważ C nie znajduje się już na ostatnim stosie.
Timmmm
1
@DanielLew W APIDemos jest tak wiele przykładów. Sugerowałbyś nazwę przykładu?
Stephane
52

Tak, spójrz na Intent.FLAG_ACTIVITY_NO_HISTORY .

Matthias
źródło
46
Pamiętaj, że nie ustawia to historii dla aktywności, którą uruchamiasz. Aby nie mieć historii dla działalności, którą uruchamiasz, po prostu ustawiłem ją android:noHistory="true"w manifeście.
georgiecasey
1
To działa dobrze. Użyj, intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)aby ustawić tę flagę.
vovahost
1
@georgiecasey jest to przydatne, gdy czasami chcesz zachować to w historii, a czasami nie chcesz tego w historii.
Vihaan Verma
24

To prawdopodobnie nie jest idealny sposób na zrobienie tego. Jeśli ktoś ma lepszy sposób, nie mogę się doczekać jego wdrożenia. Oto jak ja zrealizować to zadanie szczególnego z pre-wersja-11 SDK.

w każdej klasie, którą chcesz odejść, gdy nadejdzie odpowiedni czas, musisz to zrobić:

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

wtedy ten, który musi uruchomić łańcuch popów ze stosu, musi po prostu wywołać to, gdy chcesz go zainicjować:

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

Zatem działania nie są na stosie!
Pamiętajcie, ludzie, że możecie rozpocząć działanie, a następnie rozpocząć sprzątanie za nim, wykonanie nie następuje po jednym wątku (interfejsu użytkownika).

Travis
źródło
W przypadku, gdy ktoś natknie się na to później, pomyślałem, że może to być ważne, abyś wiedział, że jeśli obrócisz ekran, Android z przyjemnością ponownie uruchomi aplikację, gdy usuniesz ostatnią aktywność ze stosu. Pamiętaj o tym!
Travis,
To dobra odpowiedź, jeśli chcesz tylko warunkowo usunąć działanie ze stosu, w zależności od tego, co użytkownik zrobi w następnej czynności +1
theMothaShip
23

Jednym ze sposobów, który działa wcześniej niż interfejs API 11, jest rozpoczęcie ActivityGameMainnajpierw, a następnie onCreaterozpoczęcie ActivitySplashScreendziałania. Nie ActivityGameMainpojawi się, gdy wywołasz funkcję startActivity zbyt wcześnie, aby rozpocząć powitanie.

Następnie można wyczyścić stos podczas uruchamiania ActivityGameMainprzez ustawienie tych flag na zamiar:

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

Musisz także dodać to do ActivitySplashScreen:

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

Aby ponowne naciśnięcie tego działania nie powróciło do twojego ActivityGameMain .

Zakładam, że nie chcesz wracać do ekranu powitalnego, aby to osiągnąć, sugeruję ustawienie go na noHistoryswoim AndroidManifest.xml. Następnie włóż goBackPressedkod do swojegoActivitySplashScreenSignUpZamiast tego klasie.

Znalazłem jednak kilka sposobów na przełamanie tego. Uruchom inną aplikację z poziomu powiadomieniaActivitySplashScreenSignUp jest wyświetlany, a historia cofania nie jest resetowana.

Jedynym realnym rozwiązaniem jest API 11:

intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
mxcl
źródło
20

Używam w ten sposób.

Intent i = new Intent(MyOldActivity.this, MyNewActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
startActivity(i);
Smiderle
źródło
Dzięki. Uznałem to za pomocne w przypadku, gdy w moim menu znajdował się przycisk Początek, i nie chciałem, aby działania po zakończeniu były wyświetlane, gdy użytkownik kliknie z tego miejsca.
ghitesh
8

Wiem, że się spóźniłem (minęły dwa lata od momentu zadania pytania), ale udało mi się to, przechwytując naciśnięcie przycisku Wstecz. Zamiast sprawdzania konkretnych działań, po prostu patrzę na liczbę, a jeśli jest mniejsza niż 3, po prostu wysyła aplikację do tyłu (wstrzymuje aplikację i przywraca użytkownika do tego, co działało przed uruchomieniem). Sprawdzam mniej niż trzy, ponieważ mam tylko jeden ekran wprowadzający. Sprawdzam również liczbę, ponieważ moja aplikacja pozwala użytkownikowi na powrót do ekranu głównego poprzez menu, co pozwala mu tworzyć kopie zapasowe na innych ekranach w normalny sposób, jeśli na stosie znajdują się działania inne niż ekran wprowadzający.

//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
źródło
7

W manifeście możesz dodać:

android:noHistory="true"

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

Możesz także zadzwonić

finish()

natychmiast po wywołaniu startActivity (..)

Anubhav
źródło
2
Lepiej używać flag aktywności niż umieszczać rzeczy w manifeście.
Trevor Hart
6

Wystarczy ustawić noHistory="true"w pliku manifestu . Sprawia, że ​​aktywność jest usuwana z backstacka.

Stanisław Brzeziński
źródło
4

To szalone, że nikt nie wspomniał o tym eleganckim rozwiązaniu. To powinna być zaakceptowana odpowiedź.

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

Kluczem tutaj jest skorzystanie intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); z pośrednika Activity. Gdy ten środkowy link zostanie zerwany, DashActivitytestament pierwszy i ostatni na stosie.

android:noHistory="true"jest złym rozwiązaniem, ponieważ powoduje problemy, gdy polega się na Activitywywołaniu zwrotnym, np onActivityResult. Jest to zalecane rozwiązanie i należy je zaakceptować.

Rowland Mtetezi
źródło
1
Ta flaga brzmiała zbyt dobrze, aby mogła być prawdziwa. FLAG_ACTIVITY_NO_HISTORY działa ładnie i zgodnie z oczekiwaniami, dopóki aplikacja nie znajdzie się w tle, a następnie na pierwszym planie, mając aktywność z flagą na szczycie stosu. Po przejściu w tło aktywność jest niszczona. Po powrocie do aplikacji zobaczysz poprzednią aktywność ze stosu. Zdecydowanie nie chciałem takiego zachowania.
NeverwinterMoon
4

Jest za późno, ale mam nadzieję, że to pomoże. Większość odpowiedzi nie wskazuje właściwego kierunku. Są na to dwie proste flagi.

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

Z dokumentów Androida:

public static final int FLAG_ACTIVITY_CLEAR_TASK Dodano w interfejsie API na poziomie 11

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

działanie do wyczyszczenia przed rozpoczęciem działania. Oznacza to, że aktywność staje się nowym katalogiem głównym pustego zadania, a wszelkie stare działania są zakończone. Można tego użyć tylko w połączeniu z FLAG_ACTIVITY_NEW_TASK.

Nouman Ghaffar
źródło
1

Po prostu wywołaj this.finish () przed startActivity (intent) w ten sposób:

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

źródło
użytkownicy, którzy mają błąd w „tym”, powinni zmienić go na „ActivityOne.this”
ninbit
1

Usuwanie działania z Historii odbywa się poprzez ustawienie flagi przed działaniem, którego nie chcesz

A-> B-> C-> D

Załóżmy, że A, B, C i D to 4 czynności, jeśli chcesz wyczyścić B i C, a następnie ustawić flagę

intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);

W ćwiczeniach A i B

Oto bit kodu

Intent intent = new Intent(this,Activity_B.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
startActivity(intent);
ricky
źródło
0
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            super.finishAndRemoveTask();
        }
        else {
            super.finish();
        }
chętny książę
źródło
-7

Spróbuj tego:

intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)

to poziom API 1, sprawdź link .

Alécio Carvalho
źródło
2
Co to ma zrobić? Zdecydowanie nie rozwiązuje tego problemu.
rodrigo-silveira
Jesteś pewien, że nie miałeś na myśli Intent.FLAG_ACTIVITY_NO_HISTORY?
Riot Goes Woof