18

does the launchMode of the launcher activity in the manifest get ignored? The android documentation says that the default launchMode is "standard" but this isn't logic for me if this would be applied to the main activity of an app because each time you start the app, another task would be created in the instance of the app.

Praveen Sharma
  • 4,326
  • 5
  • 25
  • 45
David
  • 3,971
  • 1
  • 26
  • 65
  • The question is perfectly well formulated and it does still require an answer. For example, if you have a simple test application with omitted `launchMode`, which is supposed to mean "standard", then every tap on this app in the launcher should start new task. But this is not the case (at least in Android 6.0.1). If the app is already running, the launcher brings the old instance to foreground. – Stan Dec 16 '15 at 20:21

5 Answers5

10

Well, I delved into Android sources myself and found the following thing.

The launcher starts apps using the method startActivityAsUser in LauncherAppsService. The intent is constructed using these lines:

Intent launchIntent = new Intent(Intent.ACTION_MAIN);
launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
launchIntent.setComponent(component);
launchIntent.setSourceBounds(sourceBounds);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

According to Android documentation, the flag FLAG_ACTIVITY_NEW_TASK means:

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.

This effectively and unconditionally overrides launchMode specified (or omitted to default behaviour) in the app, and ignores this attribute.

I think this demonstrates that the documentation is not clear (or complete) enough. Without such deep investigations of the core source codes everyone can get unexpected results now and then.

Dhaval Parmar
  • 18,812
  • 8
  • 82
  • 177
Stan
  • 8,683
  • 9
  • 58
  • 102
8

You are confusing two things. One is launchMode and the other is "what happens when the user selects an app icon from the HOME screen, or selects a task from the list of recent tasks". These are 2 completely different things.

launchMode

Each Activity has a specified launchMode (the default is "standard" or "multiple". This tells Android how to start this Activity, and there are many factors that can contribute to the "interpretation" of the launchMode. It depends on what other flags may have been specified in the Intent used. It depends on which task requested the launch of the Activity (or if the launch was requested from a non-activity context, like from a Service or BroadcastReceiver). It depends on whether or not an existing instance of the Activity is already active in the specified task, etc.

Behaviour on selecting an app icon from the HOME screen or list of installed applications

When the user selects an app icon, startActivity() is called with an Intent containing the following data:

  • ACTION=MAIN
  • CATEGORY=LAUNCHER
  • Component is set to the package name and the class name of the Activity that is defined in the manifest with ACTION=MAIN and CATEGORY=LAUNCHER
  • Flag FLAG_ACTIVITY_NEW_TASK and FLAG_ACTIVITY_RESET_TASK_IF_NEEDED are set.

Regardless of the launchMode definition of the Activity to be launched, calling startActivity() with an Intent like this causes the following behaviour:

If there is already an existing task whose task affinity matches the Activity being started (in simple terms, if the app is already running), Android will simply bring the existing task to the foreground. That's it. It doesn't create an instance of any Activity. It doesn't call onNewIntent() on any Activity. It does nothing other than bringing the existing task to the foreground. This is why, even if you specify launchMode="standard" for your launcher Activity, Android doesn't create a new instance every time you click on your app icon.

If there isn't already an existing task whose task affinity matches the Activity being started (in simple terms, if the app isn't already running), Android will create a new task and launch the Activity into that task. launchMode doesn't play a role here, since there is absolutely no difference between the launch modes when launching a single Activity into a new task. Android always creates a new task and always creates a new instance of the Activity as the root of that task.

This behaviour is also the same when the user selectsa task from the list of recent tasks. If the task is still running, Android just brings the task to the foreground, does not start any new Activity instances and does not call onNewIntent(). If the task is no longer running, Android creates a new task and launches the launcher Activity into that task. The only difference here is that the flag FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY is also set in the Intent if the user selected a task from the list of recent tasks.

I hope this answers your question.

See this answer for a very detailed explanation of FLAG_ACTIVITY_RESET_TASK_IF_NEEDED and task reparenting in general.

Community
  • 1
  • 1
David Wasser
  • 93,459
  • 16
  • 209
  • 274
  • Thank you for the answer. I don't think that I'm confusing the 2 things. Both my and your answers mean basically the same: `launchMode` does not take effect in many cases and is overridden by an "external" intent, and this should be described in the `launchMode` documentation with more details, IMHO. – Stan Dec 23 '15 at 18:06
  • Sounds to me like the original poster of the question was confusing 2 things. Also, there are lots of things that have dependencies on other things. Almost all flags, settings, conditions, etc. in Android have to be taken within a certain context. In general, I agree, that the documentation could be improved. However if all the "ifs, buts, and whenevers" were described in the documentation it would become so confusing to read it that most new developers would just go code for iOS. – David Wasser Dec 23 '15 at 19:51
  • Referring to the original post again: The reason that Android doesn't create another instance of the `Activity` when the user starts the app again has nothing at all to do with `launchMode`. It wouldn't make any difference what `launchMode` was specified. The behaviour simply has nothing to do with `launchMode`. It also has nothing to do with what color the main window's background is, or what font is being used, or what the phase of the moon is. I don't see why this should be specified in the documentation. – David Wasser Dec 23 '15 at 19:55
  • Your last comment sounds like `launchMode` is useless.or misleading. This is indeed "An instruction on how the activity _should_ be launched.", but not how it must and will be actually launched. – Stan Dec 24 '15 at 09:09
  • I'm not saying that `launchMode` is useless or misleading. I am saying that there are other factors that can modify the behaviour as specified by `launchMode`. Task affinity, launch context and `Intent` flags can all have an effect on what Android actually does when calling `startActivity()`. – David Wasser Dec 24 '15 at 17:41
  • "Regardless of the launchMode definition of the Activity to be launched,...It doesn't create an instance of any Activity." This is not entirely true. Selecting app icon for activity with`singleTask` will def have different behavior: https://stackoverflow.com/a/3002890 – tir38 Oct 04 '19 at 19:35
  • This is not true, if you set launchMode to "signgleTask" for Launcher Activity. Everytime you click app icon on launcher app, onNewIntent of Laucher Activity will be called. – Charlesjean Apr 10 '20 at 08:34
2

Think of everything except the opening activity as an abstract implementation. Declaring an activity as

        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

Will cause it to open first. Subsequent activities are Overriden at the time an Intent is formed to navigate between activities. The overrides are represented as intent flags.

A list of intent extras: http://developer.android.com/reference/android/content/Intent.html

With flags being commands you'd otherwise have written in the Manifest.

KoalaKoalified
  • 687
  • 4
  • 15
  • The analogy to `abstract implementation` is weird and wrong. This just adds a lot more confusion to an already confusing issue. How do these answers get upvotes? – David Wasser Dec 23 '15 at 19:58
  • Well regardless of what intent filters you place on subsequent activities declared in your manifest, they get overriden when you declare an Intent to go to those activities in your code. Basically the same as when you have an abstract class or a class that extends a class with a method you want changed. The original intention no longer occurs unless a call to super is there – KoalaKoalified Dec 23 '15 at 21:06
  • Sorry, that statement makes no sense at all. You are again confusing things. ``s don't get overridden. Intent filters are used when launching activities using **implicit** Intents. Intent filters are not used if you launch an `Activity` using an **explicit** Intent. This isn't in any way related to abstrations, inheritance and overriding. – David Wasser Dec 24 '15 at 17:37
0

You are right.The default mode is "standard".

According to android documentation

*In standard mode ,Every time there's a new intent for a "standard" activity, a new instance of the class is created to respond to that intent. Each instance handles a single intent.

*.If the parent activity has launch mode standard (and the up intent does not contain FLAG_ACTIVITY_CLEAR_TOP), the current activity and its parent are both popped off the stack, and a new instance of the parent activity is created to receive the navigation intent.

SachinS
  • 2,223
  • 1
  • 15
  • 25
0

The behavior of Activity set to standard mode is a new Activity will always be created to work separately with each Intent sent. Imagine, if there are 10 Intents sent to compose an email, there should be 10 Activities launch to serve each Intent separately. As a result, there could be an unlimited number of this kind of Activity launched in a device.

Behavior on Android pre-Lollipop

standard Activity would be created and placed on top of stack in the same task as one that sent an Intent. For example, when we share an image from gallery to a standard Activity, It will be stacked in the same task as described although they are from the different application. If we switch the application to the another one and then switch back to Gallery, we will still see that standard launchMode place on top of Gallery's task. As a result, if we need to do anything with Gallery, we have to finish our job in that additional Activity first.

enter image description here

Behavior on Android Lollipop

If the Activities are from the same application, it will work just like on pre-Lollipop, stacked on top of the task. But in case that an Intent is sent from a different application. New task will be created and the newly created Activity will be placed as a root Activity like below.

enter image description here

Source from here

Prasad
  • 3,462
  • 1
  • 23
  • 28