ChatGPT解决这个技术问题 Extra ChatGPT

Clear the entire history stack and start a new activity on Android

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.


C
Community

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.


Just to clarify, use this: intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
without the Intent.FLAG_ACTIVITY_NEW_TASK the app sometimes just closes itself on android 4
IntentCompat has a flag to clear task now as well, so you can support pre API level 11 - developer.android.com/reference/android/support/v4/content/…
IntentCompat.FLAG_ACTIVITY_CLEAR_TASK is ignored on devices with API level < 10. developer.android.com/reference/android/support/v4/content/…
IntentCompat's flag is only to avoid a crash, but doesn't do anything as @David says.
m
monish george

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.


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 :)
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
k
karan

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.


This did the trick, the flags werent working on 4.x.x for me and this worked perfectly! Thanks
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.
u
user2895402

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

do you mean CLEAR_TASK instead of CLEAR_TOP?
K
Keith Maurino

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.


+1 Nice solution to prevent exactly one activity in a certain situation from beeing put onto the history stack.
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....
S
Shankar Agarwal

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:

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 :)


In the end I decide to leave the Stack intact and just tell the user that their current screen was invalid
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.
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.
@Arhimed Are there other issues? The memory leak can be patched up by keeping only weak references.
@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.
G
Gibolt

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
}

S
Sagar Zala

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

if am using like this activityis updated once again call api but previously existing all statck is cleared
P
Pang

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

A
Amir Hossein Ghasemi

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)

J
Joaquin Iurchuk
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);

R
RajeshkumarG

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.


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);
T
Tauseef

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.


This aproachment can cause issues on Android 6.0+, if you ask for permitions in this Activity.