I want to program Home button, so it will remove all Activities in stack, except one. I did it like in here: How to finish every activity on the stack except the first in Android
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
Intent intent = new Intent(this, AMainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
break;
...
but this way doesn't suit me, because it removes ALL Activities (including the first one) and starts the first one again. For example - if I check user password in onCreate(), he would be asked again.
How to remove all Activities from stack, but so the first one will not be "touched" ?
add following property to your AMainActivity's Activity tag in your manifest.xml.
android:launchMode="singleTop"
Yes, according to the documentation of Intent.FLAG_ACTIVITY_CLEAR_TOP:
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().
So, use additional Intent flag:
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
And your activity should not be recreated. Instead, it will just get the new intent delivered via a call to onNewIntent().
You can use ExcludeFromRecent = "true" flag in Activities declaration in manifest, which you don’t want to be in Stack.
Related
I have 5 different activities in my app, i enable the user to navigate between those activities by clicking buttons. The main activity has a RecyclerView in it (used to make a feed). the other activities are used for search, profile, notifications, etc. The user opens the app, the main activity is displayed. The user can scroll through the feed (which is the RecyclerView) in the main activity, now the user decides to go to other activities, search, profile, etc. Now, when the user clicks on the button that navigates to the main activity, I want to open back the main activity and display the recycler view at the same scrolling position and with the same items as was when the user just left it off.
Note: I'm not talking here about pressing the back button or using any goBack functions. I want to enable the user to use the main activity and visit all other activities and after all of that he will be able to come back to the main activity and find the feed exactly as he left it off.
In every activity I have five navigation buttons that allowing the user to go from every activity to every activity: click on profileBtn will open the profile activity, etc.
There is a way in which i can back up the state of the recycler view in the main activity before the user wants to go to other activities and restore it when the user clicks on the homeBtn?
Code:
HomeActivity.java:
public void profileBtn_OnClick(android.view.View view)
{
Intent intent = new Intent(getBaseContext(), ProfileActivity.class);
startActivity(intent);
}
ProfileActivity.java, SerachActivity.java, NotificationsActivity.java:
public void homeBtn_OnClick(android.view.View view)
{
/* HERE I WANT TO OPEN BACK THE HOME ACTIVITY AND DISPLAY THE FEED
EXACTLY AS IT WAS WHEN THE USER LEFT IT, HOW DO I DO THAT? */
Intent intent = new Intent(getBaseContext(), HomeActivity.class);
startActivity(intent);
}
You can use the launchMode="singleTask".
The system creates the activity at the root of a new task and routes
the intent to it. However, if an instance of the activity already
exists, the system routes the intent to the existing instance through
a call to its onNewIntent() method, rather than creating a new one.
You can get more information about launchMode here: https://developer.android.com/guide/topics/manifest/activity-element
android:launchMode=["standard" | "singleTop" | "singleTask" | "singleInstance"]
<activity
android:name=".ui.HomeActivity"
android:launchMode="singleTask" />
Please do NOT use the special launch mode singleTask for this purpose. It causes more problems than it solves. These launch modes have complex side-effects that are not obvious and will cause you more problems later.
Your problem is simple to solve using standard Android behaviour. Change your method to look like this:
public void homeBtn_OnClick(android.view.View view)
{
Intent intent = new Intent(getBaseContext(), HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(intent);
}
The flag CLEAR_TOP tells Android to remove all activities from the task that are on top of the target Activity (in this case the target Activity is HomeActivity.
The flag SINGLE_TOP tells Android not to recreate HomeActivity, but to reuse the existing instance of it.
Let me explain detailed; I have notification and this notification opens B activity with two cases.
Cases :
If app is closed. (not running on background)
If app is opened. (on background or front)
Case-1
I click to the notification and it opens the B activity with case-1. When i press back i want to go to the A activity and kill B activity. I dont need B activity anymore. Everything easy from here without using flags. When I'm on B activity and press back two times from here, it goes A activity and then closes the app. My trouble here is, if i open the app from navigation buttons of phone (can't remember the name of this button) app is opening from B activity. That's not what i expected. I want to open A activity. Don't want to see B activity anymore.
Case-2
I click to the notification and it opens the B activity with case-2.When i press back i want to bring A activity to the front, without creating anything new. If i press back on B activity, two times and close the app and then again re-open app from navigation button of phone, want to open app from A activity.
So how can i make this correctly, i tried to use flags (i already read docs) but couldn't get work.
What flags should i use when i open the B activity and onBackPress method of B activity to go A activity as i wanted
This should be achievable by adding
android:launchMode="singleTask"
to the A activity in the Manifest, then you can just open A activity from B activity onBackPressed and you will have A only once in the stack.
If it's not working the way you want, you can create an abstract class that extends Activity and handle the stack in a static object, then A & B must extend this new class
try this
Intent intent = new Intent(context, YourActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
try this
android:launchMode="singleTask" in android manifest file
You can achive this by adding FLAG_ACTIVITY_REORDER_TO_FRONT
Intent i = new Intent(context, Activity.class);
i.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(i);
You May try this isTaskRoot() Which will return B is root
if it is true then launch A
other wise you may finish B
B Activity
#Override
public void onBackPressed() {
if (isTaskRoot()) {
//call A which is not exist
Intent i =new Intent(B.this,A.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(i);
}else {
//Finish B if A Already Exixt
finish();
}
}
You can call B Activity on Notification Click
if A is present then u can finish B else you can launch A
If set FLAG_ACTIVITY_CLEAR_TOP, 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.
Just put this in ActivityB onBackPressed:
Intent i = new Intent(ActivityB.this , ActivityA.calss);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivity(i);
finish();
How solve case 1:
finish(); on ActivityB BackPressed method make ActivityB finish after open ActivityA. So after opens ActivtyA, ActivityB will shut down.
How solve case 2:
With this combination flag, It will do what you want. It will close all activities in stack and just keep destination activity. If instance of activity exist it will use it and calls OnNewInstance and if not it will creates new one.
If this is the only instance of Activity B being used, you can add the flag noHistory to the manifest for Activity B
android:noHistory="true"
This will stop Activity B being added to the back stack, this is also possible dynamically by using the Intent Flag FLAG_ACTIVITY_NO_HISTORY when calling Activity B.
As for having Activity A start when Activity B is killed #Quentin Menini's answer of having a single task activity set in the manifest will work if that is the only way you wish Activity A to be accessed, or the Intent Flag Intent.FLAG_ACTIVITY_REORDER_TO_FRONT as #Naimish Vinchhi has suggested, will have the desired effect in this instance.
https://developer.android.com/reference/android/content/Intent.html
link to see all possible Intent flags
https://developer.android.com/guide/topics/manifest/activity-element.html
link for all possible manifest activity options
How to prevent to create every time Instance of Store activity?
When I call startActivity(new Intent(this,StoreActivity.class)), it will create new instance and call OnCreate Method in StoreActivity. I want to call one time Oncreate.
Is this Possible ?
Do this
startActivity(new Intent(
this,StoreActivity.class).setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP));
From Android Documentation
public static final int FLAG_ACTIVITY_SINGLE_TOP
If set, the activity will not be launched if it is already running at the top of the history stack.
Constant Value: 536870912 (0x20000000)
Start your activity like this:
Intent storeIntent = new Intent(this, StoreActivity.class);
storeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(storeIntent);
It will call onCreate() only once on first launch of activity, if activity is already running it calls only onNewIntent() instead of create new instance of activity or calling onCreate.
This is not possible since each time you press back button, onBackPressed() method is called which actually destroys your StoreActivity.
If you want this method to not destroy your activity, just remove or comment out super.onBackPressed() line in this method.
In this case your activity will not be destroyed when back button is pressed, but then you will have to use any other logic to bring your MainActivity to top of the stack.
try to finish the first activity after starting the new one,
add this code after the Intent command.
finish();
like that:
startActivity(new Intent(this, newActivity.class));
finish();
check this link
Finish an activity from another activity
I have 4 pages.
From page_1 > page_2 > page_3 > page_4.
Once the user reaches page_3 and clicks a button, it navigates to page_4. Once the button is clicked, I want to clear all the navigation history so when the user goes back on page_4, the app quits rather than going back to page_3.
I've tried:
Intent intent = new Intent(this, page_4.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
But nothing happens. I can still go back to page_3, page_2 etc. How do I make it so that when the user clicks on the button on page_3, he goes to page_4 and from page_4 there shouldn't be any navigation history?
I'm not sure that these methods will works for you. The first method is by adding FLAG_ACTIVITY_TASK_ON_HOME when you go to page_4 from page_3:
Intent intent = new Intent(this, page_4.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME);
startActivity(intent);
So once you press BACK button within page_4, it directs you to HOME activity (MainActivity) first, then you can press BACK button again to exit the app from this activity.
From the docs:
If set in an Intent passed to Context.startActivity(), this flag will cause a newly launching task to be placed on top of the current home activity task (if there is one). That is, pressing back from the task will always return the user to home even if that was not the last activity they saw. This can only be used in conjunction with FLAG_ACTIVITY_NEW_TASK.
The second way is, set android:noHistory="true" within the activity in manifest. Apply this attribute for page_1 till page_4. But this method has two disadvantages. First, your activity is completely has no back stack. The second, the activities you set with this attribute get destroyed once you press HOME button or when you get an incoming call. I never found this topic, so please CMIIW.
for all the other activities like page_3,page_2,page_1,
Use FLAG_ACTIVITY_NO_HISTORY(If set, the new activity is not kept in the history stack.) :
intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
Try set Intent.FLAG_ACTIVITY_NO_HISTORY And Intent.FLAG_ACTIVITY_TASK_ON_HOME
From documentation
Intent.FLAG_ACTIVITY_NO_HISTORY
If set, the new activity is not kept in the history stack. As soon as
the user navigates away from it, the activity is finished. This may
also be set with the noHistory attribute.
Intent.FLAG_ACTIVITY_TASK_ON_HOME
If set in an Intent passed to
Context.startActivity(), this flag will cause a newly launching task
to be placed on top of the current home activity task (if there is
one). That is, pressing back from the task will always return the user
to home even if that was not the last activity they saw. This can only
be used in conjunction with FLAG_ACTIVITY_NEW_TASK.
I've read through several posts about using this but must be missing something as it's not working for me. My activity A has launchmode="singleTop" in the manifest. It starts activity B, with launchmode="singleInstance". Activity B opens a browser and receives an intent back, which is why it's singleInstance. I'm trying to override the back button so that the user is sent back to activity A, and can then press Back to leave the activity, rather than back to activity B again.
// activity B
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR
&& keyCode == KeyEvent.KEYCODE_BACK
&& event.getRepeatCount() == 0) onBackPressed();
return super.onKeyDown(keyCode, event);
}
#Override
public void onBackPressed() {
startActivity(new Intent(this, UI.class)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
return;
}
After returning from the browser, the stack is...
A,B,Browser,B
I expect this code to change the stack to...
A
... so that pressing back once more takes the user back to the Home Screen.
Instead, it seems to change the stack to...
A,B,Browser,B,A
...as though those flags aren't there.
I tried calling finish() in activity B after startActivity, but then the back button takes me back to the browser again!
What am I missing?
I have started Activity A->B->C->D.
When the back button is pressed on Activity D I want to go to Activity A. Since A is my starting point and therefore already on the stack all the activities in top of A is cleared and you can't go back to any other Activity from A.
This actually works in my code:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
Intent a = new Intent(this,A.class);
a.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(a);
return true;
}
return super.onKeyDown(keyCode, event);
}
#bitestar has the correct solution, but there is one more step:
It was hidden away in the docs, however you must change the launchMode of the Activity to anything other than standard. Otherwise it will be destroyed and recreated instead of being reset to the top.
For this, I use FLAG_ACTIVITY_CLEAR_TOP flag for starting Intent(without FLAG_ACTIVITY_NEW_TASK)
and launchMode = "singleTask" in manifest for launched activity.
Seems like it works as I need - activity does not restart and all other activities are closed.
Though this question already has sufficient answers, I thought somebody would want to know why this flag works in this peculiar manner, This is what I found in Android documentation
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().
So, Either,
1. Change the launchMode of the Activity A to something else from standard (ie. singleTask or something). Then your flag FLAG_ACTIVITY_CLEAR_TOP will not restart your Activity A.
or,
2. Use Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP as your flag. Then it will work the way you desire.
I use three flags to resolve the problem:
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|
Intent.FLAG_ACTIVITY_CLEAR_TASK |
Intent.FLAG_ACTIVITY_NEW_TASK);
Add android:noHistory="true" in manifest file .
<manifest >
<activity
android:name="UI"
android:noHistory="true"/>
</manifest>
i called activity_name.this.finish() after starting new intent and it worked for me.
I tried "FLAG_ACTIVITY_CLEAR_TOP" and "FLAG_ACTIVITY_NEW_TASK"
But it won't work for me... I am not suggesting this solution for use but if setting flag won't work for you than you can try this..But still i recommend don't use it
I know that there's already an accepted answer, but I don't see how it works for the OP because I don't think FLAG_ACTIVITY_CLEAR_TOP is meaningful in his particular case. That flag is relevant only with activities in the same task. Based on his description, each activity is in its own task: A, B, and the browser.
Something that is maybe throwing him off is that A is singleTop, when it should be singleTask. If A is singleTop, and B starts A, then a new A will be created because A is not in B's task. From the documentation for singleTop:
"If an instance of the activity already exists at the top of the current task, the system routes the intent to that instance..."
Since B starts A, the current task is B's task, which is for a singleInstance and therefore cannot include A. Use singleTask to achieve the desired result there because then the system will find the task that has A and bring that task to the foreground.
Lastly, after B has started A, and the user presses back from A, the OP does not want to see either B or the browser. To achieve this, calling finish() in B is correct; again, FLAG_ACTIVITY_CLEAR_TOP won't remove the other activities in A's task because his other activities are all in different tasks. The piece that he was missing, though is that B should also use FLAG_ACTIVITY_NO_HISTORY when firing the intent for the browser. Note: if the browser is already running prior to even starting the OP's application, then of course you will see the browser when pressing back from A. So to really test this, be sure to back out of the browser before starting the application.
FLAG_ACTIVITY_NEW_TASK is the problem here which initiates a new task .Just remove it & you are done.
Well I recommend you to read what every Flag does before working with them
Read this & Intent Flags here
Initially, I also had a problem getting FLAG_ACTIVITY_CLEAR_TOP to work. Eventually, I got it to work by using the value of it (0x04000000). So looks like there's an Eclipse/compiler issue. But unfortunately, the surviving activity is restarted, which is not what I want. So looks like there's no easy solution.