This question already has answers here:
Resume application and stack from notification
(8 answers)
Closed 6 years ago.
Right now I'm using a PendingIntent to launch my desired Activity from the Notification. But I want to know if it's possible to reuse the current app instance.
For example:
Launch app, the Launcher Activity is called HomeActivity
Navigate to SecondActivity
Press the home button
Click on the notification from the app and resume SecondActivity
But if the user didn't navigate to the SecondActivity i want to open the HomeActivity when I click on the Notification. I would be glad for any help regarding this problem :)
But I want to know if it's possible to reuse the current app instance.
Yes, you can reuse if the app is in background. In PendingIntent you will pass an Intent, so in that Intent you should set a flag like intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); so if the app is in background it will just bring activity to front.
According to android docs :
FLAG_ACTIVITY_NEW_TASK
Added in API level 1 int FLAG_ACTIVITY_NEW_TASK If set, this activity
will become the start of a new task on this history stack. A task
(from the activity that started it to the next task activity) defines
an atomic group of activities that the user can move to. Tasks can be
moved to the foreground and background; all of the activities inside
of a particular task always remain in the same order. See Tasks and
Back Stack for more information about tasks.
This flag is generally used by activities that want to present a
"launcher" style behavior: they give the user a list of separate
things that can be done, which otherwise run completely independently
of the activity launching them.
When using this flag, 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 of the
screen with the state it was last in. See FLAG_ACTIVITY_MULTIPLE_TASK
for a flag to disable this behavior.
This flag can not be used when the caller is requesting a result from
the activity being launched.
Check the docs here
But if the user didn't navigate to the SecondActivity i want to open the HomeActivity.
Why do you launch HomeActivity if your notification intent class you are creating have SecondActivity as the launcher. It will create a new SecondActivity and launches it if it is not in background.
EDIT: If you want to relaunch app where you left off try like this :
final Intent resumeIntent = new Intent(context, YourLauncher.class);
resumeIntent.setAction("android.intent.action.MAIN");
resumeIntent.addCategory("android.intent.category.LAUNCHER");
final PendingIntent resumePendingIntent = PendingIntent.getActivity(context, 0, resumeIntent, 0);
Here YourLauncher.class is the launcher class name.
Related
What happens when you click on an app's launch icon?
Is a new intent always sent, or is the result sometimes the same as resuming a task from recent tasks?
If an intent is sent, when does it get sent to the onCreate() method of a new activity instance and when does it get routed through onNewIntent() of an existing activity?
Let's suppose the intent gets routed through onNewIntent() of an existing activity in the task. Which activity does it get sent to? The one nearest the top or the one nearest the root? Will it always get sent to an instance of the application's launch activity or can it sometimes get sent to an activity with the same affinity as the root? Can it ever get sent to an activity which does not share the same affinity as the root?
Finally, how is this all affected by the various launch modes (standard, single top, single instance, single task) of the activities in the task?
If there is anyone out there who understands all this, please help me!
What happens when you click on an app's launch icon?
Launcher apps calls startActivity with an intent [action = Intent.ACTION_MAIN, category = Intent.CATEGORY_LAUNCHER and flag = Intent.FLAG_ACTIVITY_NEW_TASK].
Regarding Intent.FLAG_ACTIVITY_NEW_TASK, from docs:
When using this flag, 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 of the
screen with the state it was last in.
onNewIntent basics:
onNewIntent is delivered only when activity has set either singleTask, singleInstance launch modes. It is also delivered if activity has set singleTop launch mode or the intent to start the activity has set the flag FLAG_ACTIVITY_SINGLE_TOP and the activity instance is already at the top of the target task. It means an attempt was made to launch a new instance of activity, instead the existing instance itself need to handle the intent.
Here is the response to your queries:
Is a new intent always sent, or is the result sometimes the same as
resuming a task from recent tasks?
If the task is already running, it is brought to foreground. In case FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET flag was used to launch a activity and latter the task is brought to foreground, then the activity is killed. From docs:
This is useful for cases where you have a logical break in your
application. For example, an e-mail application may have a command to
view an attachment, which launches an image view activity to display
it. This activity should be part of the e-mail application's task,
since it is a part of the task the user is involved in. However, if
the user leaves that task, and later selects the e-mail app from home,
we may like them to return to the conversation they were viewing, not
the picture attachment, since that is confusing. By setting this flag
when launching the image viewer, that viewer and any activities it
starts will be removed the next time the user returns to mail.
-
If an intent is sent, when does it get sent to the onCreate() method
of a new activity instance and when does it get routed through
onNewIntent() of an existing activity?
onCreate is called while creating a new instance of activity. onNewIntent is called if already an activity instance exists and no new instance need to be created, as in case of singleInstance, singleTask and conditionally singleTop (as described above).
Let's suppose the intent gets routed through onNewIntent() of an
existing activity in the task. Which activity does it get sent to? The
one nearest the top or the one nearest the root? Will it always get
sent to an instance of the application's launch activity or can it
sometimes get sent to an activity with the same affinity as the root?
Can it ever get sent to an activity which does not share the same
affinity as the root?
In case of singleTask and singleInstance it has to be root of the task. In case of singleTop it has to be top activity of the task.
Finally, how is this all affected by the various launch modes
(standard, single top, single instance, single task) of the activities
in the task?
I hope the explanation provided till now, answers it.
Update 1:
Here is the Launcher code which adds the flags to intent:
void processShortcut(Intent intent) {
....
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
....
}
void startActivitySafely(Intent intent) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
...
startActivity(intent);
}
Your best bet is to read through the Developer docs here: http://developer.android.com/training/basics/activity-lifecycle/index.html
There is a flow chart in the first lesson(http://developer.android.com/images/training/basics/basic-lifecycle.png) which provides an excellent graphical representation of the Android activity life-cycle.
I have an odd issue with my application.
I start the application and the activity shows ok.
I then press the home key so that the activity goes into the background. I can see the onPause() method being called.
The application's service then creates a notification which shows on the status bar.
I then click on the notification and the activity is shown and I see that the onResume() method is called.
I then press the home key and the activity goes into the background. I can see the onPause() method being called.
If I now start the application by clicking on the applications icon I see that a new instance of the activity is created rather than using the paused instance.
If I press the home key again the new activity goes into the background.
Starting the application by clicking on the applications icon I see another new instance of the activity is created.
Pressing the back button at the point destroys each activity in return.
What I want to happen is that a single instance of the activity be used.
Any ideas?
Just use the same intent filters as android uses when launches the app:
final Intent notificationIntent = new Intent(context, MessageListActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
As the intent you created to open your activity from notification bar is the same as android used for launching your app, the previously opened activity will be shown instead of creating a new one.
You should look at the different launch modes for Android activities. this should help. Launch modes can be set in the androidmanifest.xml file. I think your solution would be to use the 'singleTop' launch mode.
I know there's been a few posts for what I'm about to ask but I can't find any with the right answer.
From my understanding, if your main activity's (let's call it A) launchMode is set to singleTask, and A has initiated activity B then a click to the home button will destroy the history stack and re-launching the application will take you back to A and not B.
I have launchMode set to singleTask because I have a persistent notification and I don't want to have multiple instances of the main activity to appear whenever the user clicks on the notification.
Is there something I'm missing that would allow me to cater for both?
So I'm asking if there's a way I can ensure that whenever the user wishes to launch the app, from the notification or not, to take him back to the last (current) activity.
If I change launchMode to singleTop it works but I get multiple instances of the main activity whenever I launch it.
Thanks
Andreas
Have you tried setting launchMode to singleTop to all the activities in your app?? Because what i get from your query is that the main activity isn't singleTop, so that might lead to another instance of the main activity being called once the main activity is launched from the activity that was launched from the notification activity.
Or you can specify the launchMode as an attribute to the application tag itself in the manifest.
I use the following code to avoid multiple instances of the activity
Intent intent=new Intent(this,RICO.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
Changing manifest doesn't look appropriate to me
I'm having issues with both the approches.
The notification works flawless only in this condition:
- using the back button in the main activity (with the history containing only the that activity)
- not using the Home button
- not using the notification IF the activity you are calling is on top and active
In any other case, the notification cannot anymore call on the foreground the activity by using "new Intent(...)"
I've found the alchemical combination of manifest options and intent's flags for getting what I needed:
Intent intent= new Intent(this, YaampActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
using these options
android:launchMode="singleTask"
android:taskAffinity=""
android:excludeFromRecents="true"
inside the element.
Now I've a notification which spawns the main activity (if that activity is not already in the foreground) and its behavior is correct even if the activity is "closed" by pressing the home button and/or the back one.
I've searched and searched and searched for this!
So I've got an app widget and it has a configuration activity that I can open when pressing a button on the app. The scenario is:
Had the app opened.
Closed the app with the home button.
Selected to add my widget
I have configured the widget.
Placed on my home screen
Then open the configuration activity again with the button on the widget.
Cancel the new config by pressing back will put me back into the app.
When pressing back I want to just return home.
Basically what I'm asking is. How do I start the configuration activity in it's own task/stack?
I've looked into intent filters but I'm just not quite sure, or maybe it's something to do with the package it's in, or maybe it's just not possible!
I suppose it may have something to do with the intent I use to launch the config activity
Intent configIntent = new Intent(this, Configuration.class);
configIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
remoteView.setOnClickPendingIntent(R.id.config, PendingIntent.getActivity(this, 0, configIntent, PendingIntent.FLAG_UPDATE_CURRENT));
Perhaps because I launch it with 'this' as the context, it will always start in my applications stack...
but the pending intent api is:
PendingIntent API 1
"Note that the activity will be started outside of the context of an existing activity"
So yeah I'll stop talking now as I just end up going in circles!
EDIT
So tried android:launchMode="singleInstance" in the manifest like was stated. This worked however it stops the 'startActivityForResult' behaviour working correctly. (which is the whole reason for a config activity) Get the error:
WARN/ActivityManager(59): Activity is launching as a new task, so cancelling activity result.
So still haven't found a solution.
Ok sorted it :-) needed:
android:taskAffinity=""
in the manifest, setting the task affinity to an empty string allows for the activity to start in it's own stack, as it is not 'affiliated' with the rest of the application.
UPDATE
I have changed the task affinity to:
android:taskAffinity="com.my.package.alternative.task"
as each time I launched the activity it was showing up multiple times in the 'history'. So it now starts in it's own stack but is shared with other instances of the same activity.
Also need to add the Flag Intent.FLAG_ACTIVITY_NO_HISTORY to your intent :-) this stops your getting your application multiple time's in the history when you 'press and hold' the home button.
UPDATE
I've noticed FLAG_ACTIVITY_NO_HISTORY wasn't doing what I wanted, I've removed it and added:
android:excludeFromRecents="true"
into the activity tag in the manifest as well. The activity now behaves like I want :-)
Got this answer from the following link trail:
Tasks & Back Stack |
Managing Tasks |
Affiliation Tag
Try to put android:launchMode="singleInstance" for an activity of the app in AndroidManifest.xml
Say that the user has started my App and then switched off to use the Browser (so we have 2 sets of Tasks running). After a while, something happens to my app that requires the user's attention, so it posts a notification to notify the user. Is there a way to bring my App's task (and the Activity on top of the stack) out from the background when user clicks on my notification?
In your notification you call an intent to start your app, if you ensure it has the following flags then it will be brought to front rather than creating another instance:
Intent contentIntent = new Intent(this, ABC.class);
contentIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | INTENT.FLAG_ACTIVITY_SINGLE_TOP);
A notification usually comes with a PendingIntent (Notification.contentIntent). Set this intent to your app to start an activity of your app.
There is only one Activity that is currently active - as soon as you switch to a different screen, the system will pause your activity (onPause, and very likely onDestroy), so you'll need to use an intent to bring resume your activity and bring it to the main screen.