FLAG_ACTIVITY_CLEAR_TOP does not work as expected - android

I have 4 activities A, B, C, D, E with each declared as android:launchMode="singleInstance" and A being parentActivity of B, and B being parent Activity of C, in manifest.
Now user navigated to E like this: A > B > C > D > E.
And I have a button in E with the following onClickListener
Intent intent = new Intent(E.this, C.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
What I need? (Also according to documentation, if I understood it right, this should happen)
Activities D and E should be cleared from stack
Activity C should be resumed receiving the intent (as singleInstance is set, it will not be created newly)
I want this stack: C | B | A
What's happening?
Activity C is resumed receiving the intent
Activities D and E are NOT cleared from stack. I can click back button again and again to see E, D, B, A.
I get this stack: C | E | D | B | A
PS: My question is very similar to this however, the answers given there does not suit this question. Some answers I found there and elsewhere:
I can't use NEW_TASK flag, as I need to keep A, B in stack alive.
I can't use startActivityForResult() on D and then finish() it which in fact is a hack, as I have other decisive factors in E such as delivering the intent to some other activity depending on user input.
I can't finish() activity D, while delivering intent to E, and then finish() E while hitting C, which would actually solve the problem. But, if back is pressed on E, i want it go back to D and not C.
When I try finish() on E as soon as I do startactivity(intent) after setting flags, it just finishes E, but not D.

Artem Mostyaev's comment solves the puzzle! Use singleTask
So what exactly was the mistake?
When singleInstance is used as launchMode, and when an activity is launched, Android makes sure that it is launched in a new task as if NEW_TASK flag is added, with itself being the only activity inside it.
So when user navigated to E, the stack was never like [ A | B | C | D | E ]
Instead there were five different tasks like [A] [B] [C] [D] [E].
And when I tried E > C with CLEAR_TOP, it indeed searched for C in its task and tried to clear all activities after C. But C was never there in the task where E resides.
So it tried launching a new activity C, but then as I set launchMode to singleInstance, it had no way other than bringing [C] front while leaving other tasks untouched.
So how singleTask worked?
It created the stack like I wanted [ A | B | C | D | E ] and CLEAR_TOP worked as expected. Done!

The problem is in android:launchMode="singleInstance". According to the documentation for singleInstance:
If this activity tries to start a new activity, that new activity will
be launched in a separate task.
So, your activity D is launched as the new task, and that's why it is not deleted.

Related

Android Activity history tracking and clearing partially

Imagine this activity history stack:
A > B > C > D > E
scenario 1:
If the user is on E then on tapping the back button it should navigate to D > C > B > A.
scenario 2:
If the user is on E then on tapping a custom button "Show B", then it should clear E > D > C. Which is similar to Finish().
Like X > Y if we set finish on Y the X will be displayed. Similar If I tape Show B on E then E > D > C should be cleared from the stack.
I need to achieve both scenarios.
(Edited ^^^^ with scenarios)
If the user is on E activity and wants to move B. If B is in history stack can we clear C > D > E so that user can navigate to B without startActivity(B). and A should be in history.
If an activity is available in the stack then it should load from history if not startActivity(B).
If I use FLAG_ACTIVITY_CLEAR_TOP/FLAG_ACTIVITY_NEW_TASK, it will clear full history and start's new activity.
I want to clear partial history.
Will it be possible to achieve? If so, how to do it please?
This is all pretty standard. Don't use any special launch modes. Normally, pressing BACK will just finish the current Activity and drop you back into the previous one.
For this case:
If the user is on E then on tapping a custom button "Show B", then it
should clear E > D > C. Which is similar to Finish().
In E, to go back to the existing instance of B, do this:
Intent intent = new Intent(this, B.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
This will finish E, D and C and return to the existing instance of B.
The flag FLAG_ACTIVITY_CLEAR_TOP tells Android to clear all activities between the current Activity and the target Activity. If you don't specify FLAG_ACTIVITY_SINGLE_TOP then the existing instance of the target Activity will also be finished and a new instance will be created. If you do specify FLAG_ACTIVITY_SINGLE_TOP then the existing instance of the target Activity will NOT be finished and a new instance will NOT be created.
You can achieve this using
android:launchMode="singleTask"
in your manifest file. For more refer this documentation https://android.jlelse.eu/android-activity-launch-mode-e0df1aa72242

Android lauchmode and single instance

I don't understand how to do my use case between the launchmode of activity and the flag of intent.
What i want to do :
A => B => C => B when i back B => C => A
In other word, i want to have a single instance of all activity in the stack and if i recall one of the single instance the activity go to top of stack (with reset or destroy + recreate don't have importance, id o my logic of creation in onresume so), exception for my custom splashscreen (but i resolve this one with noHistory for this activity "splashscreen").
I tried standard mode with flag
Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP or with this flag Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT but that don't have the behavior that i want.
So if you can tell me which launchmode and/or flag i should use for made what i want, i would be grateful.
FLAG_ACTIVITY_REORDER_TO_FRONT seems appropriate in your case:
FLAG_ACTIVITY_REORDER_TO_FRONT
If set in an Intent passed to Context.startActivity(), this flag will cause the launched activity to be brought to the front of its task's history stack if it is already running.
For example, consider a task consisting of four activities: A, B, C, D. If D calls startActivity() with an Intent that resolves to the component of activity B, then B will be brought to the front of the history stack, with this resulting order: A, C, D, B. This flag will be ignored if FLAG_ACTIVITY_CLEAR_TOP is also specified.
If we leave out Activity D in the above description we get:
A, B, C (start B) => A, C, B
Which appears to be what you want.

FLAG_ACTIVITY_NEW_TASK not working as expected

I have a stack with 3 Activities: A, B, C. From Activity C I start the Activity B setting on the Intent the flag: FLAG_ACTIVITY_NEW_TASK. According to the documentation this should bring the Activity B with the underlying task on the front resulting in a stack : A, B, C, A, B.
However the actual stack is A, B, C, B. When I press the Back-Button from the Activity B I go through the above stack in the reverse order: B -> C -> B -> A.
The code which starts the the Activity B from Activity C is:
Intent intent = new Intent(this, B.class);
intent.setFlag(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
According to the docs the flag FLAG_ACTIVITY_NEW_TASK causes the same behavour as the "singleTask" launchMode value. If I set in the AndroidManifest.xml file the launchmode "singletask" on the Activity B, then it produces the expected behavour as described in the docs: the task A, B comes to the front resulting in a stack A, B, C, A, B.
Why does not it work with the flag FLAG_ACTIVITY_NEW_TASK? Is some affinity configuaration also necessary in this case?

Android back stack - Go back to a certain activity in back stack

I have activities A -> B -> C -> D. How can I open the existing B from activity D clearing C and D? I would end up with A -> B. I don't want to recreate a new B.
I think you must use FLAG_ACTIVITY_CLEAR_TOP and FLAG_ACTIVITY_SINGLE_TOP.
According to the doc:
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.
The currently running instance of activity B in the above example will
either receive the new intent you are starting here in its
onNewIntent() method, or be itself finished and restarted with the new
intent. If it has declared its launch mode to be "multiple" (the
default) and you have not set FLAG_ACTIVITY_SINGLE_TOP in the same
intent, then it will be finished and re-created; for all other launch
modes or if FLAG_ACTIVITY_SINGLE_TOP is set then this Intent will be
delivered to the current instance's onNewIntent().
You can declare you target activity's(Activity B in your situation) Mode of SingleTop in Manifest file like
<activity android:name="YourActivityName" android:launchMode="singleTop"></activity>
Then startActivity for navigating to this Activity will end C and D and wont start a new Activity B
Right after you finish dealing with C and D, you can just finish() the activities.

Remove Activities from Stack History in Android

So ..
let's Suppose the Following Sequence of Activities
A -> B -> C -> D -> E
if I do The Action1 in E I just want remove E from stack and go Back To D.
on the Other hand, If I do The Action2 in E, I want to remove E and D from stack and return to C
how to do that ?
the above sequence is simple implement of messaging App, so A is The Log in Activity and B is The Profile Activity and C show the Friend Request List and D show the Profile of selected person form C, and in C there are 2 button one for approved and the second for cancel requset, now if click any of them it take him to E where Yes or No to do the Opperation, if No it return to profile of Selected person , of yes it should return to C
Well what you can do is that when you go from A->B call finish(); to end activity A, same for B->C, that is end B. So by the time you reach E, only E will be active. So now when you do Action1, call Activity D, and when you do Action2 call activity C. And this time call finish(); on E. This would do exactly what you want.
Every time when you move from one Activity to another you can add this flag with the intent Intent.FLAG_ACTIVITY_CLEAR_TOP. This will clear your all previous activities so that in Activity E there will be no Activity in Stack.
If it always the last activity who is going to perform this kind of action then you can start that last activity for result. So when D is spawning E, do it using startActivityForResult (Intent intent, int requestCode). And later when you perform actions in E, call finish() for E and before doing that pass a result code to D. Based on that result you can either do nothing (so D will remain as it is) or you can call finish() on D as well.
if by stack u mean recent application then to clear recent application you can add
android:excludeFromRecents="true"
inside your activity tag in manifest.xml
If Action1 do nothing since if a user press the Back button, E will be removed and you are back to D. If Action2, start C with flag Intent.FLAG_ACTIVITY_CLEAR_TOP, the D and E would be cleared from the stack

Categories

Resources