Android Activity Launch Mode
π Tasks & the Back Stack
Before diving into launch modes, itβs important to understand tasks and the back stack.
A task is a collection of activities that a user interacts with when performing a job. Activities in a task are arranged in a back stack β a last-in, first-out (LIFO) structure.
1
2
3
4
5
6
7
8
9
10
Task (Back Stack)
ββββββββββββββββ
β Activity D β β Top (current foreground)
ββββββββββββββββ€
β Activity C β
ββββββββββββββββ€
β Activity B β
ββββββββββββββββ€
β Activity A β β Bottom (root)
ββββββββββββββββ
- When a new activity is started, it is pushed onto the top of the stack.
- When the user presses Back, the current activity is popped off the stack and the one underneath becomes active.
- The task moves to the background when the user navigates to the home screen, but the back stack is preserved.
π What is Launch Mode?
Launch mode defines how a new instance of an activity is created when it is started, and how it interacts with the current task and back stack.
You can set launch mode in two ways:
1. AndroidManifest.xml β applies to all launches of the activity:
1
2
3
<activity
android:name=".MyActivity"
android:launchMode="singleTop" />
2. Intent flags β applies dynamically per-launch, overrides manifest:
1
2
3
val intent = Intent(this, MyActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
startActivity(intent)
π΅ The Four Launch Modes
1. standard (Default)
| Property | Value |
|---|---|
| Multiple instances? | β Yes |
| Must be on top to reuse? | N/A β always creates new |
onNewIntent() called? | β No |
| Own task? | β No |
Behavior: Every startActivity() call creates a brand new instance of the activity, regardless of whether one already exists in the stack. Multiple instances can exist in the same task or in different tasks.
1
2
3
4
Start A β Start B β Start A β Start A
Back Stack: [ A | B | A | A ]
β top
Use case: Most activities β detail screens, editor screens, forms. Each instance holds independent state (e.g., EmailDetailActivity showing a different email each time).
2. singleTop
| Property | Value |
|---|---|
| Multiple instances? | β Yes (but not consecutive duplicates on top) |
| Must be on top to reuse? | β Yes |
onNewIntent() called? | β Yes (when reused) |
| Own task? | β No |
Behavior: If an instance of the activity is already at the top of the current taskβs back stack, the system does not create a new instance. Instead, it delivers the new intent to the existing instance via onNewIntent(). If the activity is anywhere else (not at top), a new instance is created normally.
1
2
3
4
5
Back Stack: [ A | B | C ] β Start C again β [ A | B | C ]
β onNewIntent() called
Back Stack: [ A | B | C ] β Start B β [ A | B | C | B ]
β new instance (B not on top)
1
2
3
4
5
6
override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
// Handle the new intent (e.g., update search query)
val newQuery = intent.getStringExtra("QUERY")
performSearch(newQuery)
}
Use case: Search results screen, notification-triggered screens. Prevents stacking duplicate activities when a user taps a notification while that screen is already open.
3. singleTask
| Property | Value |
|---|---|
| Multiple instances? | β No (only one globally) |
| Must be on top to reuse? | β No β found anywhere in its task |
onNewIntent() called? | β Yes |
| Own task? | β Yes (acts as root of its task) |
Behavior: Only one instance can exist in the entire system. If the activity already exists, the system brings its task to the foreground, clears all activities above it in that task (they are destroyed), and delivers the new intent via onNewIntent(). If no instance exists, a new task is created with the activity as its root.
1
2
3
4
Task: [ A | B | C | D ] β Start C (singleTask)
Result: [ A | B | C ]
β D was destroyed, onNewIntent() called on C
1
2
3
4
<activity
android:name=".MainActivity"
android:launchMode="singleTask"
android:taskAffinity="" />
Use case: Main/home screen of an app, dashboard activity. Ensures the user always returns to a single, consistent entry point regardless of how deep they navigated.
β οΈ Warning: Activities above the
singleTaskactivity in the stack are permanently destroyed when it is re-launched. Make sure they donβt hold unsaved state.
4. singleInstance
| Property | Value |
|---|---|
| Multiple instances? | β No (only one globally) |
| Must be on top to reuse? | β No |
onNewIntent() called? | β Yes |
| Own task? | β Yes β exclusively, no other activity can join |
Behavior: Like singleTask, but even more isolated. The activity lives in its own dedicated task and no other activity can be launched into that task. Any activity started from a singleInstance activity is placed in a different task.
1
2
3
4
5
6
App Task: [ A | B ] Singleton Task: [ D ]
β start D (singleInstance)
App Task: [ A | B ] Singleton Task: [ D ] β D gets its own task
Start E from D:
App Task: [ A | B | E ] Singleton Task: [ D ] β E is in the app task, not D's task
Use case: System-level screens that must be completely isolated β a dialer, in-app browser, camera, or any screen shared across apps via an implicit intent.
β οΈ Note: Pressing Back from a
singleInstanceactivity may feel unintuitive to users since the task boundary is hidden from them.
5. singleInstancePerTask (API 31+)
| Property | Value |
|---|---|
| Multiple instances? | β Yes (one per task) |
| Must be on top to reuse? | β No |
onNewIntent() called? | β Yes (when reused in same task) |
| Own task? | β Yes (as root), but other activities CAN join |
Behavior: Introduced in Android 12 (API 31). Only one instance per task is allowed. Unlike singleInstance, other activities can be launched into the same task. If the activity already exists as the root of a task, launching it again clears activities above it and calls onNewIntent(). Multiple instances can exist, but each must reside in a different task.
1
2
3
<activity
android:name=".FlowRootActivity"
android:launchMode="singleInstancePerTask" />
Use case: Root activity of a flow that can be launched into multiple tasks simultaneously (e.g., multi-window scenarios, split-screen flows).
π Launch Mode Comparison
| Launch Mode | New Instance? | onNewIntent()? | Own Task? | Multiple Instances? |
|---|---|---|---|---|
standard | Always | β | β | β |
singleTop | Only if not on top | β (when reused) | β | β |
singleTask | Only if none exists | β (when reused) | β | β |
singleInstance | Only if none exists | β (when reused) | β (exclusive) | β |
singleInstancePerTask | One per task | β (when reused) | β (non-exclusive) | β (one per task) |
π·οΈ Common Intent Flags
Intent flags let you dynamically control launch behavior at the call site, complementing (or overriding) manifest-declared launch modes.
| Flag | Behavior |
|---|---|
FLAG_ACTIVITY_NEW_TASK | Equivalent to singleTask. Launches in a new task. Required when starting activities from non-Activity contexts (e.g., Service, BroadcastReceiver). |
FLAG_ACTIVITY_SINGLE_TOP | Equivalent to singleTop. Reuses the activity if itβs on top. |
FLAG_ACTIVITY_CLEAR_TOP | If the target activity exists in the task, all activities above it are destroyed. Often paired with FLAG_ACTIVITY_NEW_TASK. |
FLAG_ACTIVITY_CLEAR_TASK | Clears the entire existing task before launching. Must be combined with FLAG_ACTIVITY_NEW_TASK. Useful for post-logout navigation. |
FLAG_ACTIVITY_NO_HISTORY | The activity is not kept in the back stack. It is finished as soon as the user leaves it. |
FLAG_ACTIVITY_REORDER_TO_FRONT | If the activity already exists in the task, it is moved to the top of the stack without clearing activities above it. |
Common Combination: Logout & Clear Task
1
2
3
4
5
// Navigate to LoginActivity after logout, clearing all previous screens
val intent = Intent(this, LoginActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
startActivity(intent)
Combination: Deep Link to Existing Screen
1
2
3
4
5
// If HomeActivity exists in the stack, bring it to top and clear activities above it
val intent = Intent(this, HomeActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
}
startActivity(intent)
β Rule of thumb: Intent flags take precedence over manifest-declared
launchModewhen both are specified and they conflict.
π‘ Quick-Reference: Which Mode to Use?
| Scenario | Recommended Mode |
|---|---|
| General-purpose screen | standard |
| Prevent back-stack spam from notifications | singleTop |
| App home / dashboard that resets navigation | singleTask |
| Fully isolated screen shared across apps | singleInstance |
| Flow root that supports multi-window | singleInstancePerTask |
| Clear everything and restart (logout) | FLAG_ACTIVITY_NEW_TASK \| FLAG_ACTIVITY_CLEAR_TASK |