374

Is it possible to start an activity on the stack, clearing the entire history before it?

The situation

I have an activity stack that either goes A->B->C or B->C (screen A selects the users token, but many users only have a single token).

In screen C the user may take an action which makes screen B invalid, so the application wants to take them to screen A, regardless of whether it is already in the stack. Screen A should then be the only item on the stack in my application.

Notes

There are many other similar questions, but I haven't found anything that answers this exact question. I tried calling getParent().finish() - this always results in a null pointer exception. FLAG_ACTIVITY_CLEAR_TOP only works if the activity is already on the stack.

Marian Paździoch
  • 8,813
  • 10
  • 58
  • 103
Casebash
  • 114,675
  • 90
  • 247
  • 350

14 Answers14

731

In API level 11 a new Intent Flag was added just for this: Intent.FLAG_ACTIVITY_CLEAR_TASK

Just to clarify, use this:

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

Unfortunately for API lvl <= 10, I haven't yet found a clean solution to this. The "DontHackAndroidLikeThis" solution is indeed pure hackery. You should not do that. :)

Edit: As per @Ben Pearson's comment, for API <=10 now one can use IntentCompat class for the same. One can use IntentCompat.FLAG_ACTIVITY_CLEAR_TASK flag to clear task. So you can support pre API level 11 as well.

Community
  • 1
  • 1
Akos Cz
  • 12,711
  • 1
  • 37
  • 32
  • 26
    Just to clarify, use this: intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); – user123321 Mar 12 '12 at 18:18
  • 2
    without the Intent.FLAG_ACTIVITY_NEW_TASK the app sometimes just closes itself on android 4 – max4ever Oct 12 '12 at 15:00
  • 22
    IntentCompat has a flag to clear task now as well, so you can support pre API level 11 - http://developer.android.com/reference/android/support/v4/content/IntentCompat.html#FLAG_ACTIVITY_CLEAR_TASK – Ben Pearson Dec 12 '13 at 12:34
  • @BenPearson's comment helped. That can be added to the answer. – Shobhit Puri Feb 18 '14 at 18:22
  • this is great because I can have a "loading" screen and the user can't use the back button to return to the loading screen after the main activity is shown. – Someone Somewhere Apr 26 '14 at 20:38
  • 10
    IntentCompat.FLAG_ACTIVITY_CLEAR_TASK is ignored on devices with API level < 10. http://developer.android.com/reference/android/support/v4/content/IntentCompat.html#FLAG_ACTIVITY_CLEAR_TASK – David Jun 09 '14 at 20:11
  • 7
    IntentCompat's flag is only to avoid a crash, but doesn't do anything as @David says. – Sloy Aug 18 '14 at 08:44
  • any one have solution for this ?http://stackoverflow.com/questions/29364638/custom-uri-navigation-from-notification-and-from-browser – Karthikeyan Ve Mar 31 '15 at 10:33
  • 1
    I'm the only one to have a temporarily activity before to see my activity (which is not really cool) with these flags ? – mrroboaat Apr 23 '15 at 10:00
  • But the transition animation is working the wrong way now using those flags. The new activity should move in from the right, but it moves in from the left now. – stoefln Nov 03 '15 at 14:05
  • I like it! Solved my problem. – jray0039 Dec 15 '15 at 21:31
55

Case 1:Only two activity A and B:

Here Activity flow is A->B .On clicking backbutton from B we need to close the application then while starting Activity B from A just call finish() this will prevent android from storing Activity A in to the Backstack.eg for activity A is Loding/Splash screen of application.

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

Case 2:More than two activitiy:

If there is a flow like A->B->C->D->B and on clicking back button in Activity B while coming from Activity D.In that case we should use.

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

Here Activity B will be started from the backstack rather than a new instance because of Intent.FLAG_ACTIVITY_CLEAR_TOP and Intent.FLAG_ACTIVITY_NEW_TASK clears the stack and makes it the top one.So when we press back button the whole application will be terminated.

monish george
  • 811
  • 7
  • 14
  • 2
    This worked for me. I put in ALL activities those flags. In those activities back buttons work perfectly going to the previous activity, and in the main Activity with Intent intent = new Intent(Intent.ACTION_MAIN); intent.addCategory(Intent.CATEGORY_HOME); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent); finish(); The whole app is closed, still in memory but no active, and if u restart the app goes to the splash screen :) – Rako Jul 19 '13 at 10:50
  • This should be the best answer. If anyone has a scenario the same with me: A->B->C->D->E->(B) From E->B should have a result: A->B – Shem Alexis Chavez Jun 14 '19 at 10:06
54

With Android's Newer Version >= API 16 use finishAffinity()

approach is suitable for >= API 16.

Intent mIntent = new Intent(mContext,MainActivity.class);
finishAffinity();
startActivity(mIntent);
  • Its is same as starting new Activity, and clear all stack.
  • OR Restart to MainActivity/FirstActivity.
karan
  • 3,319
  • 1
  • 35
  • 44
  • 1
    This did the trick, the flags werent working on 4.x.x for me and this worked perfectly! Thanks – Jonathan Aste Sep 23 '16 at 18:57
  • 1
    This seems to be the correct answer if your goal is to finish all activities below and including the current activity and start a new activity in their own task. – ToBe Apr 11 '18 at 12:25
26

I spent a few hours on this too ... and agree that FLAG_ACTIVITY_CLEAR_TOP sounds like what you'd want: clear the entire stack, except for the activity being launched, so the Back button exits the application. Yet as Mike Repass mentioned, FLAG_ACTIVITY_CLEAR_TOP only works when the activity you're launching is already in the stack; when the activity's not there, the flag doesn't do anything.

What to do? Put the activity being launching in the stack with FLAG_ACTIVITY_NEW_TASK, which makes that activity the start of a new task on the history stack. Then add the FLAG_ACTIVITY_CLEAR_TOP flag.

Now, when FLAG_ACTIVITY_CLEAR_TOP goes to find the new activity in the stack, it'll be there and be pulled up before everything else is cleared.

Here's my logout function; the View parameter is the button to which the function's attached.

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
  • 261
  • 3
  • 2
13

Immediately after you start a new activity, using startActivity, make sure you call finish() so that the current activity is not stacked behind the new one.

Keith Maurino
  • 3,374
  • 10
  • 40
  • 48
  • +1 Nice solution to prevent exactly one activity in a certain situation from beeing put onto the history stack. – marsbear Apr 27 '12 at 09:38
  • 29
    does not work if you have more than one activity in the stack the finish will just clear the previous activity but not the others.... – Necronet Aug 13 '12 at 12:20
12

You shouldn't change the stack. Android back button should work as in a web browser.

I can think of a way to do it, but it's quite a hack.

  • Make your Activities singleTask by adding it to the AndroidManifest Example:

    <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"/>
    
  • Extend Application which will hold the logic of where to go.

Example:

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

From A to B:

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

From B to C:

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

In C:

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

and handle the back button to pop() from the stack.

Once again, you shouldn't do this :)

Shankar Agarwal
  • 34,573
  • 7
  • 66
  • 64
Macarse
  • 91,829
  • 44
  • 175
  • 230
  • 1
    In the end I decide to leave the Stack intact and just tell the user that their current screen was invalid – Casebash Aug 16 '10 at 01:42
  • 1
    Very frustrating that android doesn't let us manage the activity stack this way already. I would be tempted to use this solution in my future android apps. – Cephron Feb 19 '13 at 16:14
  • 4
    Just to be clear why this should not be used: it's a nice way to create memory leaks. At some point OS may decide to kill background activities, but since `Application` takes their instances the OS will not be able to free that RAM left from the destroyed activities. – Vit Khudenko Nov 12 '13 at 12:57
  • @Arhimed Are there other issues? The memory leak can be patched up by keeping only weak references. – Navin Dec 28 '14 at 13:33
  • 1
    @Navin yes, leaks can avoided with weak refs, but if after GC there will not be a live Activity ref then the entire approach is useless. Once again - don't do this, this is a wrong approach for Android. – Vit Khudenko Dec 29 '14 at 23:30
  • @Arhimed True enough. I was just thinking of how this can be fixed, even though I will never use it. I figure that the Activity's class can be stored and used to recreate the object if/when needed. – Navin Dec 30 '14 at 03:39
  • Best and simplest solution I think before searching in 3 topic for answer. – David Jul 05 '15 at 15:09
9

Advanced Reuseable Kotlin:

You can set the flag directly using setter method. In Kotlin or is the replacement for the Java bitwise or |.

intent.flags = FLAG_ACTIVITY_NEW_TASK or FLAG_ACTIVITY_CLEAR_TASK

If you plan to use this regularly, create an Intent extension function

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

You can then directly call this function before starting the intent

intent.clearStack()

If you need the option to add additional flags in other situations, add an optional param to the extension function.

fun Intent.clearStack(additionalFlags: Int = 0) {
    flags = additionalFlags or Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
Gibolt
  • 42,564
  • 15
  • 187
  • 127
6

Try below 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);
Sagar Zala
  • 4,854
  • 9
  • 34
  • 62
  • if am using like this activityis updated once again call api but previously existing all statck is cleared – Harsha Nov 30 '18 at 11:03
5

Try this:

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();
Pang
  • 9,564
  • 146
  • 81
  • 122
Mohammad Adil
  • 503
  • 6
  • 13
5

For me none of the above methods not work.

Just do this to clear all previous activity:

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
  • 20,623
  • 10
  • 57
  • 53
2
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
Joaquin Iurchuk
  • 5,499
  • 2
  • 48
  • 64
0

In Java: -

 startActivity(new Intent(getApplicationContext(),ChooseServiceActivity.class)
                        .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
Safal Bhatia
  • 245
  • 2
  • 6
-1

Sometimes your android emulator might fails to connect eclipse DDMS tool and ask for adb to start manually. In that case you can start or stop the adb using the command prompt.

  • 1
    Sometimes your android emulator might fails to connect eclipse DDMS tool and ask for adb to start manually. In that case you can start or stop the adb using the command prompt. Intent i = new Intent(OldActivity.this, NewActivity.class); // set the new task and clear flags i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK) startActivity(i); – RajeshkumarG Oct 06 '16 at 09:11
-2

I found too simple hack just do this add new element in AndroidManifest as:-

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

the android:noHistory will clear your unwanted activity from Stack.

Tauseef
  • 117
  • 1
  • 1
  • 10