Intent.FLAG_ACTIVITY_CLEAR_TOP destroys the destination activity. How to avoid? - android

I'm trying to return back to an activity which is in the activity stack, deleting all the activitys between the current one and the destination activity.
I Readed that this is the way to achieve it:
Intent i = new Intent(SettingsActivity.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
Supposedly it will finish all the activities between the current and the destination, but also is destroying the destination activity.
This is not the behaviour I was looking for. I need to avoid the destruction of the destination activity. It should resume itself instead of being destroyed and recreated.
How can that be achieved?

You need to add FLAG_ACTIVITY_SINGLE_TOP like this:
Intent i = new Intent(SettingsActivity.this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
When you use FLAG_ACTIVITY_CLEAR_TOP, Android removes all activities on top of the target Activity including the existing instance of the target Activity and then creates a new instance of the target Activity. If you want to use the existing instance of the target Activity, you need to also specify FLAG_ACTIVITY_SINGLE_TOP.

Related

Remove all activities of an app from every existing task in Activity Back Stack

Is there a way of removing all activities belonging to the app in foreground (my app)?
The activities might be present in different tasks. Also after removing all activities my app should return to home screen which is launcher activity of my app.
Any kind of help would be greatly appreciated.
You need to call your activity like this.
Intent login=new Intent(MainActivity.this,HomeActivity.class);
login.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
login.putExtra("flag",false);
startActivity(login);
finish();
You may need
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
FLAG_ACTIVITY_CLEAR_TASK
Any existing task that would be associated with the current activity to be cleared before the desired activity is started. Simply old activities are finished.
FLAG_ACTIVITY_NEW_TASK
If set, this activity will become the start of a new task on this history stack.
for more details, Intent Flags
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);
finish();

Why does FLAG_ACTIVITY_CLEAR_TOP not work?

As the title says, Why intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) or intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) won't work?
I have 3 Activities let us say A, B and C.
When I am trying to launch Activity A from C with code:
Intent i = new Intent(this, A.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
It simply starts Activity A but doesn't clear the top.! -_-
I have also tried using setFlags().
I read different questions on SO about this problem, but I couldn't find the right answer. >_<
Somebody please help!
Edit
Code for onBackPressed() in activity 'A' as requested by #codeMagic.
#Override
public void onBackPressed(){
if(wvLogin.canGoBack())
wvLogin.goBack();
else
super.onBackPressed();
}
From the documentation for FLAG_ACTIVITY_CLEAR_TOP:
If set, and the activity being launched is already running in the
current task, then instead of launching a new instance of that
activity, all of the other activities on top of it will be closed and
this Intent will be delivered to the (now on top) old activity as a
new Intent.
As you added in your comment, the activity A has been finished before calling B, so this situation doesn't apply. A new instance of activity A will be launched instead.
As I see it, you have two options here:
1) Use the Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK flags. This will start activity A as the root of the stack. It works, but any other activities in the stack will be lost. Assuming A was the first activity (or at least, that you are not interested in any previous activities in the task stack) then it doesn't matter. Note: CLEAR_TASK requires API Level 11.
2) Another possible solution (in case the previous assumption is not true) would be to not use intent flags at all:
B starts C with startActivityForResult().
Instead of calling A, C finishes, having set a result for B indicating that A must be launched.
In B.afterActivityResult(), finish B and launch A.
You are missing the Intent.FLAG_ACTIVITY_SINGLE_TOP flag
Try this:
Intent i = new Intent(this, A.class);
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
You used a diferrent intent: use the one you initialized:
Intent i = new Intent(this, A.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); \\WRONG;;
startActivity(i);
solution:
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); \\RIGHT;;
You could either put a noHistory true to the Activity A in the manifest
android:noHistory=true

How to navigate to a particular activity?

I am having 3 activities. From the third activity, I need to come back to the 1st activity when a GUI button is clicked. I know I can click the "physical" back button 2 times to make this but that is not an option.
So, is there any way I can display the 1st activity, without creating a new instance? I can pass the 1st activity's instance to the third activity, no issue with that.
Use the FLAG_ACTIVITY_CLEAR_TOP in your intent.
From the documentation:
For example, consider a task consisting of the activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then C and D will be finished and B receive the given Intent, resulting in the stack now being: A, B.
To use:
Intent intent = new Intent(getBaseContext(), FirstActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
Intent intent = new Intent(src_ctxt, dest.class);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
src_ctxt.startActivity(intent);
This should do it
I think you need to make your activity B singleInstance that if it's already create you don't want to create again, that is launch mode of the activity can be defined in manifest android:launchMode that defines how the activity will be instanciated.
in your case use android:launchMode="singleInstance"
or
You can use flag Intent.FLAG_ACTIVITY_NEW_TASK. If the activity is already running it will bring that to front instead of creating new activity.

finish() activity twice in android?

Okay say your using a app, and you opened a new activity and then opened another, you can end the activity your on by using finish(); and your back one activity, but how can you go back two activities, all the way back to the first one? I know you could use:
Intent savedGameIntent = new Intent(v.getContext(), firstclass.class);
v.getContext().startActivity(savedGameIntent);
But is that the best way to do it?
Use the flag Intent.FLAG_ACTIVITY_CLEAR_TOP.
Intent intent = new Intent(this,A.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
From the documentation:
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
So effectively, if you have A -> B -> C, and you intent to A with that flag set, B and C will close.
I believe that will start a new activity, not back up to the original one. It sounds like you want to finish the last and middle activities. If you start the last activity with startActivityForResult, you can then override onActivityResult in the middle activity, and call finish() from there.

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.
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.
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.
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.
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();
}
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.
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 :)
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
}
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);
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();
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)
Intent i = new Intent(MainPoliticalLogin.this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);
In Java: -
startActivity(new Intent(getApplicationContext(),ChooseServiceActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK));
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.
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.

Categories

Resources