On logout, clear Activity history stack, preventing "back" button from opening logged-in-only Activities


Question

All activities in my application require a user to be logged-in to view. Users can log out from almost any activity. This is a requirement of the application. At any point if the user logs-out, I want to send the user to the Login Activity. At this point I want this activity to be at the bottom of the history stack so that pressing the "back" button returns the user to Android's home screen.

I've seen this question asked a few different places, all answered with similar answers (that I outline here), but I want to pose it here to collect feedback.

I've tried opening the Login activity by setting its Intent flags to FLAG_ACTIVITY_CLEAR_TOP which seems to do as is outlined in the documentation, but does not achieve my goal of placing the Login activity at the bottom of the history stack, and preventing the user from navigating back to previously-seen logged-in activities. I also tried using android:launchMode="singleTop" for the Login activity in the manifest, but this does not accomplish my goal either (and seems to have no effect anyway).

I believe I need to either clear the history stack, or finish all previously- opened activities.

One option is to have each activity's onCreate check logged-in status, and finish() if not logged-in. I do not like this option, as the back button will still be available for use, navigating back as activities close themselves.

The next option is to maintain a LinkedList of references to all open activities that is statically accessible from everywhere (perhaps using weak references). On logout I will access this list and iterate over all previously-opened activities, invoking finish() on each one. I'll probably begin implementing this method soon.

I'd rather use some Intent flag trickery to accomplish this, however. I'd be beyond happy to find that I can fulfill my application's requirements without having to use either of the two methods that I've outlined above.

Is there a way to accomplish this by using Intent or manifest settings, or is my second option, maintaining a LinkedList of opened activities the best option? Or is there another option that I'm completely overlooking?

1
227
9/3/2017 4:11:16 PM

Accepted Answer

I can suggest you another approach IMHO more robust. Basically you need to broadcast a logout message to all your Activities needing to stay under a logged-in status. So you can use the sendBroadcast and install a BroadcastReceiver in all your Actvities. Something like this:

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

The receiver (secured Activity):

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 **//
}
207
7/1/2015 2:33:32 AM

It seems a rite of passage that a new Android programmer spends a day researching this issue and reading all of these StackOverflow threads. I am now newly initiated and I leave here trace of my humble experience to help a future pilgrim.

First, there is no obvious or immediate way to do this per my research (as of September 2012). You'd think you could simple startActivity(new Intent(this, LoginActivity.class), CLEAR_STACK) but no.

You CAN do startActivity(new Intent(this, LoginActivity.class)) with FLAG_ACTIVITY_CLEAR_TOP - and this will cause the framework to search down the stack, find your earlier original instance of LoginActivity, recreate it and clear the rest of the (upwards) stack. And since Login is presumably at the bottom of the stack, you now have an empty stack and the Back button just exits the application.

BUT - this only works if you previously left that original instance of LoginActivity alive at the base of your stack. If, like many programmers, you chose to finish() that LoginActivity once the user has successfully logged in, then it's no longer on the base of the stack and the FLAG_ACTIVITY_CLEAR_TOP semantics do not apply ... you end up creating a new LoginActivity on top of the existing stack. Which is almost certainly NOT what you want (weird behavior where the user can 'back' their way out of login into a previous screen).

So if you have previously finish()'d the LoginActivity, you need to pursue some mechanism for clearing your stack and then starting a new LoginActivity. It seems like the answer by @doreamon in this thread is the best solution (at least to my humble eye):

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

I strongly suspect that the tricky implications of whether you leave LoginActivity alive are causing a lot of this confusion.

Good Luck.


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon