Post

Android Activity Launch Mode

Android Activity Launch Mode

Source: Android Docs β€” Tasks and the back stack


πŸ“Œ 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)

PropertyValue
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

PropertyValue
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

PropertyValue
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 singleTask activity in the stack are permanently destroyed when it is re-launched. Make sure they don’t hold unsaved state.


4. singleInstance

PropertyValue
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 singleInstance activity may feel unintuitive to users since the task boundary is hidden from them.


5. singleInstancePerTask (API 31+)

PropertyValue
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 ModeNew Instance?onNewIntent()?Own Task?Multiple Instances?
standardAlwaysβŒβŒβœ…
singleTopOnly if not on topβœ… (when reused)βŒβœ…
singleTaskOnly if none existsβœ… (when reused)βœ…βŒ
singleInstanceOnly if none existsβœ… (when reused)βœ… (exclusive)❌
singleInstancePerTaskOne 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.

FlagBehavior
FLAG_ACTIVITY_NEW_TASKEquivalent to singleTask. Launches in a new task. Required when starting activities from non-Activity contexts (e.g., Service, BroadcastReceiver).
FLAG_ACTIVITY_SINGLE_TOPEquivalent to singleTop. Reuses the activity if it’s on top.
FLAG_ACTIVITY_CLEAR_TOPIf the target activity exists in the task, all activities above it are destroyed. Often paired with FLAG_ACTIVITY_NEW_TASK.
FLAG_ACTIVITY_CLEAR_TASKClears the entire existing task before launching. Must be combined with FLAG_ACTIVITY_NEW_TASK. Useful for post-logout navigation.
FLAG_ACTIVITY_NO_HISTORYThe activity is not kept in the back stack. It is finished as soon as the user leaves it.
FLAG_ACTIVITY_REORDER_TO_FRONTIf 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)
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 launchMode when both are specified and they conflict.


πŸ’‘ Quick-Reference: Which Mode to Use?

ScenarioRecommended Mode
General-purpose screenstandard
Prevent back-stack spam from notificationssingleTop
App home / dashboard that resets navigationsingleTask
Fully isolated screen shared across appssingleInstance
Flow root that supports multi-windowsingleInstancePerTask
Clear everything and restart (logout)FLAG_ACTIVITY_NEW_TASK \| FLAG_ACTIVITY_CLEAR_TASK
This post is licensed under CC BY 4.0 by the author.