My app consists mainly of two activities, A and B, and a background service (started by alarms).
Activity A is the launcher (main) activity.
Activity B is started every now and then by the background service, with FLAG_ACTIVITY_NEW_TASK set (this is required for activity starts in bg services).
Desired behaviour: Whenever the app is left (return to homescreen, backbutton etc.) and the user returns to it, Activity A shall be resumed.
My problem: Whenever B has been started by the background service, the app will always return to B through the activity switcher (home-button long press), no matter if I have closed it via back-button or not. I can then only return to Activity A if I select the home icon of the app (because A is then started as launch activity).
I think this has to do with fact that B is started in a new task by the background service, and the app-switcher tries to return to this new task. But shouldn't the new task end when I close B via back-button, returning to A?
Can someone please explain to me what's the matter here?
The full and final solution is to add the below code to the activity in the menifest file which is opened by the service.
android:taskAffinity=""
android:excludeFromRecents="true"
android:launchMode="singleInstance"
Related
I need to launch an activity when a notification is clicked.
The Activity launched is a standalone activity and can not be opened from any other flow from the app itself. I need to ensure that no one can navigate back to this activity once it is destroyed.
Currently i am using the following configuration:
<activity android:name=".Activities.SingleRestaurantOfferActivity"
android:taskAffinity=".Activities.SingleRestaurantOfferActivity"
android:excludeFromRecents="true"
android:screenOrientation="portrait"
android:resizeableActivity="false"/>
And I am launching this activity with the intents
FLAG_ACTIVITY_CLEAR_TASK | FLAG_ACTIVITY_NEW_TASK
Now when the acitivity is created (first notification click), it creates a new task and as per my understanding, if another notification is clicked, since the task will be existing, it will clear the task and re launch the new activity with the new intent. Is my understanding correct?
If the app is open. Then the user clicks on the notification and launches the activity. Now the home button is pressed. What will happen to the notification activity? The recents screen will only show the actual app task and not the notification activity task, will the notification activity be destroyed eventually or will it leak memory?
Please guide me as to how i should approach this. The official android guide also uses launchMode:singleTask, do i need to use that as well?
I am answering my own question here so that anyone who faces a similar issue gets an idea as to what they can do.
Steps to follow are:
1) In the manifest of the required activity, add the following:
android:taskAffinity = "com.yourpackage.youractivity"
This ensures that this activity has a seperate task affinity as compared to the default affinity. This will come into picture when excludeFromRecents is added.
android:excludeFromRecents = "true"
This flag tells android that the task associated with the given activity should not be shown in recents screen. If we had not added the taskAffinity explicitly, this would have meant that the whole application would not show in the recents screen which would be irritating. adding the task affinity will only hide the task of the required activity from recents
android:noHistory = "true"
I am not sure if this is necessarily needed. I added it to ensure that as soon as the user navigates away from the activity in any way ... eg home button, it will kill the activity using onDestroy. Also exclude from recents will prevent it from showing in the recents screen.
2) Now comes the part of intent flags to launch the activity:
I have used the flags:
FLAG_ACTIVITY_NEW_TASK :
This flag along with the taskAffinity will create a new task for the activity if the task is not already created with the same affinity. Then it will place the activity at the root of this new task. If the task already exists, it will be brought to front and the new intent will be delivered to the activity in onNewIntent() method. I wanted the activity to get fully recreated so i added the other flag below.
FLAG_ACTIVITY_CLEAR_TASK:
This flag clears the task and kills all the activities in it. Then it adds the new intended activity at the root of the task. This will ensure in my case that the activity gets fully destroyed and recreated from scratch. You might not need this in your case. CLEAR_TOP with standard launch mode will also almost do the same thing but that's a whole different scenario.
Hope this helps people creating standalone activities which don't merge directly into app flows.
I have an Activity A which is declared as singleTop and android.intent.action.MAIN in Android Manifest. I start it from launcher, then launch another activity B through Intent and then press Home button. Now I have a task with activity stack "A, B" waiting in background. If I then again start activity A from launcher I get back already running instance with a stack restored (activity B running in foreground).
This is nice. And I want to achieve the same effect when launching activity A from my own Notification. I've tried different combinations of Intent flags but I've got either a new instance of activity A or the same instance but with cleared stack (no activity B in foreground).
First of all, let's make sure that the system won't kill your Activity B when you are not using that task for a long time.
If the user leaves a task for a long time, the system clears the task of all activities except the root activity. When the user returns to the task again, only the root activity is restored. The system behaves this way, because, after an extended amount of time, users likely have abandoned what they were doing before and are returning to the task to begin something new.
There are some activity attributes that you can use to modify this behavior:
alwaysRetainTaskState: If this attribute is set to "true" in the root activity of a task, the default behavior just described does not happen. The task retains all activities in its stack even after a long period. So what you need to do is to set this to true under your <activity> tag in your manifest file for A.
Second, you won't need singleTop. Check this figure from Android docs. I guess this is what you want. If you start an activity that specifies the singleTask launch mode, then if an instance of that activity exists in a background task, that whole task is brought to the foreground. At this point, the back stack now includes all activities from the task brought forward, at the top of the stack.
So you also need to add singleTask under the tag of A and B, instead of singleTop. Then, you need to launch activity A from Notification without any flags but FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_REORDER_TO_FRONT(optional).
I haven't tried this myself but I have a strong belief that it will work. Try it and let me know if it doesn't.
I need to launch an external activity (which isn't mine) for a split second, and then I have a service that launches my previous activity for the user to see.
This works great, but the problem is when the user then presses the back key, he gets to that external activity.
I have two different activity launches here, one for the external activity, and one for my activity to return to (in which I need to use FLAG_ACTIVITY_NEW_TASK because I'm launching it from a service).
For these two launches I've tried any combination of:
FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET, FLAG_ACTIVITY_NO_HISTORY, FLAG_ACTIVITY_NEW_TASK, FLAG_ACTIVITY_CLEAR_TOP, FLAG_ACTIVITY_CLEAR_TASK, FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS.
Nothing helps, I keep seeing the external activity after pressing back.
I've seen some similar questions here, but they all have the middle activity in their own app, so they can call finish on it, or set noHistory="true" in the manifest.
Any ideas?
UPDATE:
Seems like the issue is that I re-launch my previous activity from a service, which means I need to give it FLAG_ACTIVITY_NEW_TASK, from the documentation of Tasks and Back Stack:
FLAG_ACTIVITY_NEW_TASK Start the activity in a new task. If a task is
already running for the activity you are now starting, that task is
brought to the foreground with its last state restored and the
activity receives the new intent in onNewIntent(). This produces the
same behavior as the "singleTask" launchMode value, discussed in the
previous section.
And from the singleTask paragraph:
"singleTask" The system creates a new task and instantiates the activity at the root of the new task
...
Note: Although the activity starts in a
new task, the Back button still returns the user to the previous
activity.
So I need a flag that overrides this behavior somehow...
I have a Notification which starts an Activity B with FLAG_ACTIVITY_NEW_TASK. The documentation says:
[...] if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front [...]
In the case that the user taps the Notification while in Home Screen or a different app, this works fine. But if the user is in an Activity of my app, let's say in Activity "A", and then taps the Notification multiple times, Activity "B" is started multiple times. This leads to Back key not bringing back to Activity "A".
What am I doing wrong here? And where's the difference between being in home screen or a different app and being in Activity A of my app?
Regards
Now I found out that I had to set a different affinity in the manifest to start the Activity in its own task. That solved my problem, too.
You probably want FLAG_ACTIVITY_CLEAR_TOP|FLAG_ACTIVITY_SINGLE_TOP for the notification activity. That will make sure that there is only one instance of Activity B, and it is re-used .
The difference is that when your Activity A is in the foreground you already have task running , otherwise (most probably) not. Read this for more info about tasks.
Long story short, I have a LaunchActivity which is always called by LAUNCHER (i.e. the home screen). It then starts LoginActivity and then closes itself.
This is the flow:
User launches app
LaunchActivity starts, starts
LoginActivity and then calls
finish() on itself (At this point
LoginActivity is the only Activity
on the stack)
User press "Home" button, stopping
LoginActivity
User launches the app again
When the app is launched for the 2nd time, two things can happen:
LaunchActivity starts, finishes
itself and then STARTS LoginActivity
LaunchActivity starts, finishes
itself and then CREATES
LoginActivity, so there are now two
LoginActivitys on the stack.
(2) seems to happen when I restart Eclipse and the simulator (yeah I know, black magic).
Some extra info: I'm not using any start flags and my manifest doesn't have any launchModes defined.
I think you want to set android:launchMode="singleTask" There's a basic explanation here:
http://groups.google.com/group/android-developers/browse_thread/thread/e29bd82a7fec43c6/44835d74b0af3f5f?lnk=gst&q=ellipsoidmobile#44835d74b0af3f5f
From the link "If your activity is launched from another application, without using single
task, but you want this to cause your current app to come to the foreground
instead of a new instance of that activity started in the other app's task.
An example of an app that does this is the browser. "
From reading your question, this looks like what you want. Set launchMode="singleTask" on your LoginActivity and when your LaunchActivity starts the LoginActivity it should restart the existing one instead of creating a second instance.
I imagine it has to do with whether or not the LoginActivity needed to be killed while it was in the background. As the activity lifecycle explains, an activity that is stopped (not visible) can be killed if the system needs to resources.