I need the calling activity to relaunch a child. that is, if the child activity already exist, close it then launch it again. and keeping the history/relationship between the parent and child. ie when I press back from the child I want it to go to the parent
CLEAR_TOP says that it will not relaunch an activity if it already exists
NEW_TASK sounds like it will make the child activity the root of the app which I don't want
According to my understanding you have 3 requirements:
1. There is only one instance of child activity:
I don't know the reason, but if you just want to ensure the singleton of child activity on current task top, then singleTop is fine; otherwise you need to use singleTask, but then child activity will be created at the root of another task.
2. If the child already exists, close it then launch it again:
For both singleTop and singleTask, if there is already an instance of child activity (for singleTop, already an instance on current task top), the intent will be delivered to that instance. You can reset your activity status in onNewInstance(). This should have the same effects of creating a new one.
3. When I press back from the child I want to go to the parent:
For singleTop, no need to make anymore effort.
For singleTask, you can try if this tricky works: If the child activity knows what is the next activity to show by pressing back, it can manually start the parent activity by calling startActivity() in onDestroy().
More information about Android lauchMode, read http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
Use this, works for me
Intent intent = new Intent(getApplicationContext(), MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_SINGLE_TOP|Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
getApplicationContext().startActivity(intent);
Related
I want to keep a single instance of every Activity I start in my application. The launchMode singleTask was an option but it is working for only one Activity.
I want
to start an Activity if there is no instance and it is called.
and if any other instance of that Activity is present already then
that instance will brought to front without creating a new instance
of that Activity.
This property will be applied to more than one Activity.
No Activity does guarantee that it will be always on the top of the history stack.
My work until now:
I got many suggestions which are not valid for my case, so I want to point these out so that no other person would give the same suggestion.
I have set the launchMode to singleTop and this works only if the Activity is at the top of the history stack. onNewIntent() only gets called if Activity is at the top of history stack. and in my case the Activity may be at any position in stack. So this is not working.
When you launch an Activity, do it like this:
Intent intent = new Intent(this, MyActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
startActivity(intent);
If an instance of this Activity already exists, then it will be moved to the front. If an instance does NOT exist, a new instance will be created.
You can set the android:launchMode of your activity to singleTop
In this case the if the activity already exists, new intents will bring it to front will be delivered to the activity's onNewIntent()
http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
This will work if your activity is on the top of the stack.
if you want to have a single instance of the activity, then you can set your launchMode to singleTask, but this is not recommended as it will make your activity reside in a separate task , which can be confusing to the users.
Use singleTop launch mode instead (docs): if there already is an Activity instance with the same type at the top of stack in the caller Task, there would not be any new Activity created, instead an Intent will be sent to an existed Activity instance through onNewIntent() method.
See can also this article for details on launch modes.
I've read in the android docs that singleTop mode is this:
If an instance of the activity already exists at the top of the
current task, the system routes the intent to that instance through a
call to its onNewIntent() method, rather than creating a new instance
of the activity. The activity can be instantiated multiple times, each
instance can belong to different tasks, and one task can have multiple
instances (but only if the activity at the top of the back stack is
not an existing instance of the activity).
However, my app is behaving differently. My main activity has the singleTop launch mode defined in the manifest file. Here is where it's behaving oddly.
Start main activity from launcher.
From main activity, start sub activity.
When user presses back button (or actionbar home button), it sends intent to main activity with some extras. This means that main activity needs to be updated (depending on the user actions in sub activity.)
Main activity is shown with updated display.
-- the odd part is this --
From main activity, pressing back button goes back again to main activity.
Pressing back button a 2nd time brings up the launcher screen, then my app is put in the background.
On step 5, why does it bring up the main activity again? I thought singleTop will bring to front the main activity which is the current top of the stack in the task. But from that behavior in #5 and #6, it seems like it's creating two instances of main activity instead.
Is my understanding incorrect or something else is going on that I'm not clear of yet. Please help explain/clarify. Thanks.
My sub activity has its onBackPressed method overridden. And likewise, the main activity onNewIntent() handles the extras.
#Override
public void onBackPressed() {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra(MainActivity.UPDATE_ARG, true);
startActivity(intent);
super.onBackPressed();
}
Note: If I use singleTask mode, it behaves as I expected of singleTop. But I've read somewhere that singleTask and singleInstance are to be used sparingly.
From posted doc:
one task can have multiple instances (but only if the activity at the
top of the back stack is not an existing instance of the activity).
From your code:
When user presses back button (or actionbar home button), it sends
intent to main activity with some extras. This means that main
activity needs to be updated (depending on the user actions in sub
activity.)
when user presses back button your main activity dose not exist at the top of the current task and your sub activity is at the top because it has not destroyed yet, so it creates another main activity and do not use existing one because that main activity is not top.
look at this from the doc, note that the backstack contains current foreground activity:
why does it bring up the main activity again?
Well, because you're starting your activity again when you do:
startActivity(intent);
Any updates in your Activity should be performed in the onStart method (or onResume if applicable).
I've finally made sense out of all this (I think!). I'll explain.
android:launchMode attribute applies to the activity whether it's started from home launcher, from within your app (or from another app).
The intent flag Intent.FLAG_ACTIVITY_CLEAR_TOP is needed to implement the singleTop behavior. Therefore, I passed that flag when creating the intent prior to starting the activity.
For the main activity, here's what I did:
#Override
public void onBackPressed() {
Intent intent = new Intent(this, MainActivity.class);
// these flags are important!!
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(MainActivity.UPDATE_ARG, true);
startActivity(intent);
super.onBackPressed();
}
And correspondingly, I declared android:launchMode="singleTop" in the manifest file.
I have set setDisplayHomeAsUpEnabled to true and when home is pressed I want the user to go back to the very first Activity.
But in case FirstActivity already is created I don't want to recreate it. I'm currently adding FLAG_ACTIVITY_CLEAR_TOP to the intent that starts FirstActivity. Are there other flags I need to add (or use another flag altogether)
to get the desired behaviour of only creating the Activity if it doesn't exist or is the flag I have sufficient?
you can use singleTop launchmode and override onNewIntent method (this will be called if activity is relaunched instead of new one )
you can't assume that root activity is still alive, In Android 4.0 and greater devices have the developer option called don't keep activities, if it's enabled when you leave from one activity to another the parent activity automatically killed by the system.
I have a Dashboard/Home Activity where I show multiple icons to different Activitys.
My requirement is that, whenever I minimize my app I want to resume to Home Activity and not to any of the child activities.
I tried
noHistory="true"
in manifest for those child activities.
But one Activity e.g. A has its own child activities.so when I go to A and then its child Activity A_1 and press back I come to Home screen.
I have tried adding flag in intent
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
But it did not work.
You can do this by setting intent flag on minimize event.
Intent intent= new Intent(A_1.this, HomeActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
A-1, is the activity from where this event has been fired, and HomeActivity is the name of home/dashboard activity class.
I think you need to use FLAG_ACTIVITY_CLEAR_TOP when you minimize the App.
Also, I guess a less elegant approach would be to call finish() in the onPause() or onStop() methods of those child activities. This will make sure they are destroyed and will not be able to be returned to.
I've start activity using startActivityForResult. Inside started activity I want to finish calling activity using finishActivityFromChild. However it doesn't work. May be there is other method for this.
Is there a reason for killing the parent activity inside the child activity? Did you just want to kill the parent immediately after starting the child? I'm not seeing the point of using startActivityForResult() if the parent activity isn't using a result returned from the child activity, and is just getting killed by the child activity.
If you simply don't need the parent activity to exist after starting a new activity, you can use the following code:
Intent intent = new Intent(this, MyNextActivity.class);
startActivity(intent);
finish();
If you wanted to actually return a result to the parent activity from the child activity, and then finish the parent activity, you would have to return to the parent activity by finishing the child activity in order for onActivityResult() inside the parent activity to be run. If the child activity needs to return a result for processing something it cannot do by itself, you may need a Service to handle it instead.
If you startActivityForResult then what would the result go to if you killed the parent activity? It might be easier to simply lock out the back-button in your child activity, so that the user would have to start the app over to get back to it. There's probably some (very unrecommended) way to get a reference to your parent activity and store it in the Application and do it that way, if you REALLY had to, but I'm sure everyone and their mother will tell you that's a terrible idea.