Przy wylogowaniu, Wyczyść stos historii aktywności, uniemożliwiając przycisk "Wstecz" otwarcie aktywności tylko dla zalogowanych

Wszystkie działania w mojej aplikacji wymagają zalogowania użytkownika, aby wyświetlić. Użytkownicy mogą wylogować się z prawie każdej aktywności. Jest to wymóg aplikacji. W każdym momencie, jeśli użytkownik wyloguje się, chcę wysłać użytkownika do loginu Activity. W tym momencie chcę, aby ta aktywność była na dole stosu historii, aby naciśnięcie przycisku "Wstecz" zwróciło użytkownika na ekran główny Androida.

Widziałem to pytanie zadawane w kilku różnych miejscach, wszystkie odpowiedzi były podobne odpowiedzi (które opisuję tutaj), ale chcę je tutaj ułożyć, aby zebrać opinie.

Próbowałem otworzyć aktywność logowania, ustawiając jej flagi Intent na FLAG_ACTIVITY_CLEAR_TOP, co wydaje się robić tak, jak opisano w dokumentacji, ale nie osiąga mojego celu umieszczenia aktywności logowania na dole stosu historii i uniemożliwienia użytkownikowi powrotu do wcześniej widzianych aktywności zalogowanych. Próbowałem również użyć android:launchMode="singleTop" do logowania w manifeście, ale nie osiągnęło to mojego cel albo (i wydaje się, że i tak nie ma efektu).

Uważam, że muszę albo wyczyścić stos historii, albo zakończyć wszystkie wcześniej otwarte działania.

Jedną z opcji jest sprawdzenie statusu zalogowanego i finish(), jeśli nie jest zalogowany. Nie podoba mi się ta opcja, ponieważ przycisk Wstecz będzie nadal dostępny do użycia, nawigując wstecz, gdy działania się zamykają.

Kolejną opcją jest utrzymanie LinkedList odniesień do wszystkich otwartych działań, które są statycznie dostępne zewsząd(być może za pomocą słabych odniesień). Po wylogowaniu uzyskam dostęp do tej listy i powtórzę wszystkie wcześniej otwarte działania, wywołując finish() na każdej z nich. Prawdopodobnie wkrótce zacznę wdrażać tę metodę.

[[11]}wolałbym jednak użyć jakiejś sztuczki z flagami, aby to osiągnąć. Byłbym niezmiernie szczęśliwy, widząc, że mogę spełnić wymagania mojej aplikacji bez konieczności korzystania z jednej z dwóch metod, które opisałem powyżej.

Czy jest sposób na aby to osiągnąć, użyj Intent lub ustawień manifestu, czy też moja druga opcja, utrzymywanie LinkedList otwartych działań jest najlepszą opcją? A może jest inna opcja, której kompletnie nie dostrzegam?

Author: CÅ“ur, 2010-06-09

18 answers

Mogę zaproponować Ci inne podejście IMHO bardziej solidne. Zasadniczo musisz wysłać wiadomość wylogowania do wszystkich swoich działań, które muszą pozostać w stanie zalogowanym. Możesz więc użyć sendBroadcast i zainstalować BroadcastReceiver we wszystkich swoich ustawieniach. Coś takiego:

/** on your logout method:**/
Intent broadcastIntent = new Intent();
broadcastIntent.setAction("com.package.ACTION_LOGOUT");
sendBroadcast(broadcastIntent);

Odbiorca (zabezpieczona aktywność):

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    /**snip **/
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("com.package.ACTION_LOGOUT");
    registerReceiver(new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d("onReceive","Logout in progress");
            //At this point you should start the login activity and finish this one
            finish();
        }
    }, intentFilter);
    //** snip **//
}
 199
Author: Francesco Laurita,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-01 02:33:32

Wydaje się, że nowy programista Androida spędza dzień badając ten problem i czytając wszystkie te wątki StackOverflow. Jestem teraz nowo zainicjowany i zostawiam tu ślad mojego pokornego doświadczenia, aby pomóc przyszłemu pielgrzymowi.

Po pierwsze, nie ma oczywistego lub natychmiastowego sposobu, aby to zrobić na podstawie moich badań (as of September 2012). można by pomyśleć, że możesz proste startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK) ale Nie .

Możesz wykonać startActivity(new Intent(this, LoginActivity.class)) za pomocą FLAG_ACTIVITY_CLEAR_TOP - a to spowoduje, że framework będzie przeszukiwał stos, znajdź wcześniejszą pierwotną instancję LoginActivity, odtworz ją i wyczyść resztę stosu (w górę). A ponieważ Logowanie jest prawdopodobnie na dole stosu, masz teraz pusty stos, a przycisk Wstecz po prostu opuszcza aplikację.

Ale - to działa tylko wtedy, gdy wcześniej pozostawiłeś oryginalną instancję LoginActivity żywą u podstawy stosu. Jeśli, podobnie jak wielu programistów, zdecydowałeś się finish(), że LoginActivity Po pomyślnym zalogowaniu się użytkownika, to nie jest już włączony podstawa stosu i semantyka FLAG_ACTIVITY_CLEAR_TOP nie mają zastosowania ... w końcu tworzysz nową LoginActivity na szczycie istniejącego stosu. Co prawie na pewno nie jest tym ,czego chcesz (dziwne zachowanie, w którym użytkownik może "cofnąć" swoje wyjście z logowania na poprzednim ekranie).

Więc jeśli masz wcześniej finish() ' d LoginActivity, musisz zastosować jakiś mechanizm do wyczyszczenia stosu, a następnie uruchomić nowy LoginActivity. Wygląda na to, że odpowiedź @doreamon w tym wątku jest najlepszym rozwiązaniem (przynajmniej dla mojego skromne oko):

Https://stackoverflow.com/a/9580057/614880

Mocno podejrzewam, że trudne implikacje tego, czy zostawisz LoginActivity przy życiu, powodują wiele tego zamieszania.

Powodzenia.
 146
Author: Mike Repass,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:32

UPDATE

Metoda super finishAffinity() pomoże zredukować kod, ale osiągnąć to samo. Zakończy bieżącą aktywność, jak również wszystkie działania w stosie, użyj getActivity().finishAffinity(), jeśli znajdujesz się w fragmencie.

finishAffinity(); 
startActivity(new Intent(mActivity, LoginActivity.class));

ORYGINALNA ODPOWIEDŹ

Załóżmy, że LoginActivity -- > HomeActivity -->... --> SettingsActivity call signOut ():

void signOut() {
    Intent intent = new Intent(this, HomeActivity.class);
    intent.putExtra("finish", true);
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); // To clean up all activities
    startActivity(intent);
    finish();
}

Strona główna:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    boolean finish = getIntent().getBooleanExtra("finish", false);
    if (finish) {
        startActivity(new Intent(mContext, LoginActivity.class));
        finish();
        return;
    }
    initializeView();
}

To działa dla mnie, mam nadzieję, że to jest pomocne również dla Ciebie. :)

 103
Author: thanhbinh84,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-24 02:54:55

Jeśli używasz API 11 lub wyższej, możesz spróbować tego: FLAG_ACTIVITY_CLEAR_TASK--wygląda na to, że odnosi się dokładnie do twojego problemu. Oczywiście tłum pre-API 11 musiałby użyć jakiejś kombinacji sprawdzania wszystkich aktywności, jak sugeruje @doreamon, lub innej sztuczki.

(również uwaga: aby tego użyć musisz przejść w FLAG_ACTIVITY_NEW_TASK)

Intent intent = new Intent(this, LoginActivity.class);
intent.putExtra("finish", true); // if you are checking for this in your other Activities
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | 
                Intent.FLAG_ACTIVITY_CLEAR_TASK |
                Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
 66
Author: xbakesx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-01 14:01:25

Nad tym też spędziłem kilka godzin ... i zgadzam się, że FLAG_ACTIVITY_CLEAR_TOP brzmi tak, jakbyś chciał: Wyczyść cały stos, z wyjątkiem uruchamianej aktywności, więc przycisk Wstecz wychodzi z aplikacji. Jednak jak wspomniał Mike Repass, FLAG_ACTIVITY_CLEAR_TOP działa tylko wtedy, gdy aktywność, którą uruchamiasz, jest już w stosie; gdy aktywności nie ma, flaga nic nie robi.

Co robić? Umieść działanie uruchamiane w stosie z FLAG_ACTIVITY_NEW_TASK , co sprawia, że ta aktywność jest początkiem nowego zadania na stosie historii. następnie Dodaj znacznik FLAG_ACTIVITY_CLEAR_TOP.

Teraz, gdy FLAG_ACTIVITY_CLEAR_TOP znajdzie nową aktywność w stosie, będzie ona tam i zostanie wyciągnięta, zanim Wszystko inne zostanie wyczyszczone.

Oto moja funkcja wylogowania; parametr widoku jest przyciskiem, do którego funkcja jest dołączona.

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();
}
 30
Author: christinac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:18:18

Wiele odpowiedzi. Może ten też pomoże -

Intent intent = new Intent(activity, SignInActivity.class)
                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
this.startActivity(intent);
this.finish();
 4
Author: Gulshan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-16 11:53:12

Użyj tego to powinno być pomocne dla Ciebie. Lekko zmodyfikowana odpowiedź xbakesx.

Intent intent = new Intent(this, LoginActivity.class);
if(Build.VERSION.SDK_INT >= 11) {
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
} else {
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
}
startActivity(intent);
 3
Author: Mohamed Ibrahim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-01 14:00:58

Przyjęte rozwiązanie nie jest poprawne, ma problemy, ponieważ używanie odbiornika nadawczego nie jest dobrym pomysłem na ten problem. Jeśli Twoja aktywność wywołała już metodę onDestroy (), nie otrzymasz receiver. Najlepszym rozwiązaniem jest posiadanie wartości logicznej na współdzielonych preferencjach i sprawdzanie jej w metodzie OnCreate () activty. Jeżeli nie powinno być wywołane, gdy użytkownik nie jest zalogowany, to Zakończ czynność. Oto przykładowy kod do tego. Tak proste i działa na każdy warunek.

protected void onResume() {
  super.onResume();
  if (isAuthRequired()) {
    checkAuthStatus();
  }
}

private void checkAuthStatus() {
  //check your shared pref value for login in this method
  if (checkIfSharedPrefLoginValueIsTrue()) {
    finish();
  }
}

boolean isAuthRequired() {
  return true;
}
 3
Author: Yekmer Simsek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-07 09:58:49

Wybrana odpowiedź jest sprytna i podstępna. Oto jak to zrobiłem:

LoginActivity jest aktywnością roota zadania, ustawioną android: noHistory= "true" do niego w manifeście.xml; Jeśli chcesz wylogować się z ustawień, możesz to zrobić jak poniżej:

    Intent i = new Intent(SettingsActivity.this, LoginActivity.class);
    i.addFlags(IntentCompat.FLAG_ACTIVITY_CLEAR_TASK
            | Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(i);
 1
Author: t-gao,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-18 13:19:14

Oto rozwiązanie, które wymyśliłem w mojej aplikacji.

W moim LoginActivity, po pomyślnym przetworzeniu loginu, uruchamiam następny inaczej w zależności od poziomu API.

Intent i = new Intent(this, MainActivity.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    startActivity(i);
    finish();
} else {
    startActivityForResult(i, REQUEST_LOGIN_GINGERBREAD);
}

Następnie w moim login Activity ' s onActivityForResult method:

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB &&
        requestCode == REQUEST_LOGIN_GINGERBREAD &&
        resultCode == Activity.RESULT_CANCELED) {
    moveTaskToBack(true);
}

Wreszcie, po przetworzeniu wylogowania w jakiejkolwiek innej aktywności:

Intent i = new Intent(this, LoginActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);

Kiedy na pierniku, sprawia, że jeśli nacisnę przycisk Wstecz od MainActivity, LoginActivity jest natychmiast Ukryty. Na plastrze miodu i Później, Właśnie kończę logowanie po przetworzeniu loginu i jest ono poprawnie odtworzone po przetworzeniu logowania.

 1
Author: seastland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-01 14:01:44

Sometime finish() not working

Rozwiązałem ten problem z

finishAffinity()

 1
Author: AJay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-31 04:43:49

Rozpocznij swoją aktywność z StartActivityForResult i podczas wylogowania Ustaw wynik i zgodnie z Twoim wynikiem Zakończ swoją aktywność

intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivityForResult(intent, BACK_SCREEN);

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    switch (requestCode) {
    case BACK_SCREEN:
        if (resultCode == REFRESH) {
            setResult(REFRESH);
            finish();
        }
        break;
    }
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        AlertDialog alertDialog = builder.create();

        alertDialog
                .setTitle((String) getResources().getText(R.string.home));
        alertDialog.setMessage((String) getResources().getText(
                R.string.gotoHome));
        alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "Yes",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,
                            int whichButton) {

                        setResult(REFRESH);
                        finish();
                    }

                });

        alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "No",
                new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog,
                            int whichButton) {
                    }
                });
        alertDialog.show();
        return true;
    } else
        return super.onKeyDown(keyCode, event);

}
 0
Author: Eby,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-12-15 12:50:34

Dostarczone rozwiązanie @ doreamon działa dobrze we wszystkich przypadkach z wyjątkiem jednego:

Jeśli po zalogowaniu, użytkownik ekranu logowania przechodzi bezpośrednio na środkowy ekran. np. W przepływie A->B->C, Przejdź jak: Login - > B - > C - > naciśnij skrót do domu. Użycie FLAG_ACTIVITY_CLEAR_TOP czyści tylko aktywność C, ponieważ dom (a) nie znajduje się w historii stosu. Naciśnięcie przycisku na ekranie doprowadzi nas z powrotem do B.

Aby rozwiązać ten problem, możemy zachować stos aktywności (Arraylist) i gdy dom jest wciśnięty, musimy zabić wszystkie działania w tym stosie.

 0
Author: Surendra Kumar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-20 11:19:00

Jest to możliwe poprzez zarządzanie flagą w SharedPreferences lub w aktywności aplikacji.

Po uruchomieniu aplikacji (na ekranie powitalnym) Ustaw flagę = false; po wylogowaniu kliknij event Ustaw flagę true i w onresume() każdej aktywności sprawdź, czy flaga jest true, a następnie wywołaj finish ().

Działa jak czar:)

 0
Author: ashutiwari4,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-31 17:48:36

Po kliknięciu wylogowania możesz wywołać to

private void GoToPreviousActivity() {
    setResult(REQUEST_CODE_LOGOUT);
    this.finish();
}

OnActivityResult () poprzedniej aktywności wywołaj powyższy kod ponownie, dopóki nie zakończysz wszystkich działań.

 0
Author: Mak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-01 14:01:38

To mi pomogło:

     // After logout redirect user to Loing Activity
    Intent i = new Intent(_context, MainActivity.class);
    // Closing all the Activities
    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);

    // Add new Flag to start new Activity
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

    // Staring Login Activity
    _context.startActivity(i);
 0
Author: Preetansh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-06-24 12:14:29

Sugerowałbym inne podejście do tego pytania. Może nie jest najbardziej wydajny, ale myślę, że jest najłatwiejszy do zastosowania i wymaga bardzo mało kodu. Zapisanie kolejnego kodu w pierwszej aktywności (aktywność logowania, w moim przypadku) nie pozwoli użytkownikowi wrócić do wcześniej rozpoczętych działań po wylogowaniu.

@Override
public void onBackPressed() {
    // disable going back to the MainActivity
    moveTaskToBack(true);
}

Zakładam, że Login jest zakończony zaraz po zalogowaniu się użytkownika, więc nie może do niego wrócić później, naciskając przycisk Wstecz. Zamiast tego użytkownik aby wylogować się prawidłowo, należy nacisnąć przycisk Wyloguj się wewnątrz aplikacji. To, co ten przycisk Wyloguj zaimplementowałby, jest prostą intencją w następujący sposób:

Intent intent = new Intent(this, LoginActivity.class);
startActivity(intent);
finish();
Wszelkie sugestie sÄ… mile widziane.
 0
Author: Nil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-12 12:07:14

Jedną z opcji jest sprawdzenie statusu zalogowanej aktywności onCreate I finish (), jeśli nie jest zalogowana. Nie podoba mi się ta opcja, ponieważ przycisk Wstecz będzie nadal dostępny do użycia, nawigując wstecz, gdy działania się zamykają.

To, co chcesz zrobić, to wywołać logout() I finish() w metodach onStop() lub onPause (). Spowoduje to zmuszenie Androida do wywołania OnCreate (), gdy aktywność zostanie przywrócona, ponieważ nie będzie już miała jej w stosie swojej aktywności. Więc zrób jak mówisz, w OnCreate() sprawdź status zalogowanego i prześlij do ekranu logowania, jeśli nie jesteś zalogowany.

Kolejną rzeczą, którą możesz zrobić, to sprawdzić status zalogowanego w onresume (), a jeśli nie jesteś zalogowany, Zakończ () i uruchom aktywność logowania.

 -1
Author: Ricardo Villamil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-09 17:52:09