144

My app has notifications, which - obviously - without any flags, start a new activity every time so I get multiple same activities running on top of each other, which is just wrong.

What I want it to do is to bring the activity specified in the notifications pending intent, to the front if it is already running, otherwise start it.

So far, the intent/pending intent for that notification I have is

private static PendingIntent prepareIntent(Context context) {
    Intent intent = new Intent(context, MainActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    return PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

and weirdly, it sometimes works, sometimes it doesn't... I feel like I've already tried every single combination of flags.

Adinia
  • 3,722
  • 5
  • 40
  • 58
urSus
  • 12,492
  • 12
  • 69
  • 89

8 Answers8

139

You can use this:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleTask"/>

which will work similar to "singleInstance" but it won't have that weird animation.

Franco
  • 2,711
  • 2
  • 20
  • 27
  • 15
    +1, you should be the accepted answer. Differences are here: http://developer.android.com/guide/topics/manifest/activity-element.html#lmode – WSBT Jun 20 '14 at 16:08
  • 1
    To clarify, use singleTask if you have multiple activities in the app and this is the parent, singleInstance if you have only one Activity. – frostymarvelous May 21 '16 at 15:49
  • 6
    If anybody like me has tried many combinations of solutions before they ended up on this site: Make sure to get rid of other changes you tried and make sure you do this change to the correct activity. Took me far too long to find out that this solution would've worked if I hadn't tried other solutions as well (e.g. overriding `onNewIntent` and setting flags) – lucidbrot Oct 09 '17 at 13:32
  • I have a map of Messenger, Activity pair. I want to display the Activity instance if I get a message from it. Is there any way of doing this. eg: HashMap.get(Messenger).bringActivityToFront(); I mean, the activity is still running. If I open recent task and click it, it will onResume(); Cant I onResume() programatically. –  Jan 29 '20 at 20:58
  • @JaveneCPPMcGowan that seems like a different question altogether, I suggest you post that as it's own question, I don't really know the answer unfortunately. – Franco Feb 05 '20 at 01:30
  • @Franco I lost my rights to post questions. Everything I ask gets downvoted. Everything I answer get downvoted. This is my only way to get information. Anyhow I found the answer. ActivityManager.moveTaskToFront(Activity.getTaskId(), flagValue); You also need to use android.permission.REORDER_TASKS. –  Feb 05 '20 at 01:41
  • Sorry to hear about that @JaveneCPPMcGowan, good that you found a solution for your problem though. – Franco Feb 06 '20 at 11:40
49

I think the best way to do it and in a simple manner is to start the activity normally, but set that activity in the manifest with the singleInstance property. With this you practically approach both issues you are having right now, by bringing the activity to the front all the time, and letting the OS automatically create a new one if no activity exists or bring to the front the currently existing activity (thanks to the singleInstance property).

This is the way an activity is declared as a single instance:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleInstance"/>

Also to avoid a choppy animation when launching through singleInstance, you could use instead "singleTask", both are very similar but the difference is explained here as per Google's documentation:

<activity 
   android:name=".YourActivity"
   android:launchMode="singleTask"/>

singleInstance is the same as "singleTask", except that the system doesn't launch any other activities into the task holding the instance. The activity is always the single and only member of its task.

Hope this helps.

Regards!

Martin Cazares
  • 13,637
  • 10
  • 47
  • 54
  • 4
    it seems to work, but now every other new activity I launch from the singleIntent MainActivity, play this weird arcing animation instead of the regular fade&scale – urSus Sep 26 '13 at 21:51
  • What about I launched a new activity every time but clear all other running instances of it, would that be possible? – urSus Sep 26 '13 at 21:53
  • Well, i don't think the animation you mention has anything to do with the "singleInstance" property, all it does is reusing existing instance, maybe that animation you are talking about is a complete different issue... – Martin Cazares Sep 26 '13 at 21:55
  • 1
    well I am testing it right now and it does. If I remove all the intent flags and just set the launchMode="singleInstance" in the manifest, the weird animation is there, if I remove it, its back to normal – urSus Sep 26 '13 at 22:01
  • Yes, according to android documentation, seems like the "init" animation is no longer there as usual because the activity is not being initialized, is just being reused... – Martin Cazares Sep 26 '13 at 22:05
  • but it happens when I launch the DetailActivity from MainActivity, which is weird, If I have MainActivity running and get notification and click it, then yes, theres no animation ("from" MainA to MainA) – urSus Sep 26 '13 at 22:13
  • Try calling this method after starting the activity: overridePendingTransition(0,0); – Martin Cazares Sep 26 '13 at 22:21
27

I think what you need is in singleTop Activity, rather than a singleTask or singleInstance.

<activity android:name=".MyActivity"
          android:launchMode="singleTop"
          ...the rest... >

What the documentation says does perfectly suit your needs:

[...] a new instance of a "singleTop" activity may also be created to handle a new intent. However, if the target task already has an existing instance of the activity at the top of its stack, that instance will receive the new intent (in an onNewIntent() call); a new instance is not created. In other circumstances — for example, if an existing instance of the "singleTop" activity is in the target task, but not at the top of the stack, or if it's at the top of a stack, but not in the target task — a new instance would be created and pushed on the stack.

On top of that (no pun intended), I had exactly the same need as you. I tested all the launchMode flags to figure out how they actually behave in practice and as a result singleTop is actually the best for this: no weird animation, app displayed once in the recent applications list (unlike singleInstance that displays it twice due to the fact it doesn't allow any other Activity to be part of its task), and proper behavious regardless the target Activity already exists or not.

Shlublu
  • 10,917
  • 4
  • 51
  • 70
24

This is old thread, but for all those who is still seeking for answer, here is my solution. It is purely in code, without manifest settings:

private static PendingIntent prepareIntent(Context context) {
  Intent intent = new Intent(context, MainActivity.class);
  intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);      
  return PendingIntent.getActivity(context, NON_ZERO_REQUEST_CODE, intent, 
    PendingIntent.FLAG_UPDATE_CURRENT);
}

Here FLAG_ACTIVITY_SINGLE_TOP opens existing activity if it is at the top of task stack. If it is not at the top, but inside stack, FLAG_ACTIVITY_CLEAR_TOP will remove all activities on top of target activity and show it. If activity is not in the task stack, new one will be created. A crucially important point to mention - second parameter of PendingIntent.getActivity(), i.e. requestCode should have non-zero value (I even called it NON_ZERO_REQUEST_CODE in my snippet), otherwise those intent flags will not work. I have no idea why it is as it is. Flag FLAG_ACTIVITY_SINGLE_TOP is interchangeable with android:launchMode="singleTop" in activity tag in manifest.

  • 5
    Fighting since hours with these flags and was wondering why changing my intent flags didnt change anything. Non-zero request code ... a crucially important point to mention!!! Works now! Thank you! – Max Power Dec 02 '19 at 17:23
  • Wow! It works! Nice! – DimanNe Jan 11 '22 at 14:51
10

I know it is old, but nothing from the above were fitting to my application.

Without changing manifests and other configuration, here is the code to bring your app back to front - or opening it when it is closed

Intent notificationIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
notificationIntent.setPackage(null); // The golden row !!!
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
Raziza O
  • 1,560
  • 1
  • 17
  • 37
3

I tried this, and it worked even though the IDE was complaining about the code

Intent notificationIntent = new Intent(THIS_CONTEXT, MainActivity.class);
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    PendingIntent intent = PendingIntent.getActivity(THIS_CONTEXT, 0, notificationIntent, Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);

    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(THIS_CONTEXT)
            .setSmallIcon(R.drawable.cast_ic_notification_0)
            .setContentTitle("Title")
            .setContentText("Content")
            .setContentIntent(intent)
            .setPriority(PRIORITY_HIGH) //private static final PRIORITY_HIGH = 5;
            .setAutoCancel(true)
            /*.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS)*/;
    NotificationManager mNotificationManager = (NotificationManager) THIS_CONTEXT.getSystemService(Context.NOTIFICATION_SERVICE);
    mNotificationManager.notify(0, mBuilder.build());
Tsepo Nkalai
  • 1,492
  • 11
  • 18
2

Since you say you want to start your activity if it's not started already, maybe you wouldn't mind restarting it. I tested a ton of suggestions and flag combinations for the intent as well, this will always bring the activity you need to the front, though it won't keep any state previously associated with it.

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_NEW_TASK);

API11+ only.

Fat Shogun
  • 987
  • 1
  • 10
  • 18
2

I had a similar issue after adding notifications as found on the android training site. None of the other answers here worked for me, however this answer did work for me. Summary:

final Intent notificationIntent = new Intent(context, YourActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
gattsbr
  • 3,762
  • 1
  • 22
  • 34
  • You're stuck down here at the bottom of the answers list but this in the one that worked for me. `android:launchMode="singleInstance"` documentation says "if it is ever launched again with the same Intent...". Therefore your solution works by recreating the Intent used to initially launch the Activity. Only difference I had was using the flag `Intent.FLAG_ACTIVITY_REORDER_TO_FRONT` – ijmacd Sep 29 '22 at 18:11