Android Performance

A Detailed Guide to Activity Launch Modes in Android

Word count: 1.8kReading time: 11 min
2019/09/01
loading

Android Activities have several critical launch modes: standard, singleTop, singleTask, and singleInstance. Each serves a specific architectural purpose. In this post, I’ll demonstrate their behaviors using a demo and visualizing the Activity Stack at each step.

An Activity Stack is a Last-In-First-Out (LIFO) data structure. Paying attention to the “Stack Content” column in the examples below will help you grasp how these modes differ in practice.

The demo code is available on GitLab: AndroidLaunchModeTest.

standard Mode

1
android:launchMode="standard"

The default mode. A new instance of the Activity is created every time it is started.

Test Trace:

  1. Launch MainActivity
    • Stack: MainActivity
  2. Launch StandardActivity
    • Stack: StandardActivity -> MainActivity
  3. Launch StandardActivity again
    • Stack: StandardActivity (new) -> StandardActivity -> MainActivity

singleTop Mode

1
android:launchMode="singleTop"

If an instance of the Activity already exists at the top of the current stack, the system routes the intent to that instance via onNewIntent(). Otherwise, a new instance is created.

Test 1: singleTopActivity is NOT at the top

SingleTop Mode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 1. Launch MainActivity
MainActivity

// Stack content
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 2. Launch StandardActivity
MainActivity -> StandardActivity

// Stack content
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 3. Launch SingleTopActivity
MainActivity -> StandardActivity -> SingleTopActivity
// Stack content
com.example.launchmodetest/.SingleTopActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------

// 4. Launch StandardActivity
MainActivity -> StandardActivity -> SingleTopActivity -> StandardActivity
// Stack content
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.SingleTopActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 5. Launch SingleTopActivity:
MainActivity -> StandardActivity -> SingleTopActivity -> StandardActivity -> SingleTopActivity
// Stack content
com.example.launchmodetest/.SingleTopActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.SingleTopActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

// Here, because the third SingleTopActivity is not at the top of the stack (StandardActivity is at the top), launching a new SingleTopActivity will create a new SingleTopActivity instance

Test 2: singleTopActivity IS at the top

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 1. Launch MainActivity
MainActivity
// Stack content
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 2. Launch StandardActivity
MainActivity -> StandardActivity
// Stack content
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 3. Launch SingleTopActivity
MainActivity -> StandardActivity -> SingleTopActivity
// Stack content
com.example.launchmodetest/.SingleTopActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 4. Launch SingleTopActivity
MainActivity -> StandardActivity -> SingleTopActivity -> SingleTopActivity
// Stack content
com.example.launchmodetest/.SingleTopActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

// SingleTopActivity receives am_new_intent instead of creating a new Activity

singleTask Mode

1
android:launchMode="singleTask"
  1. Without taskAffinity, a singleTask Activity is created within the current Task.
  2. singleTask follows an “in-stack reuse” pattern: if the Activity doesn’t exist in the current Task, a new instance is created; if it already exists anywhere in the Task, that instance is reused (receiving onNewIntent).
  3. When reusing an existing instance, all Activities above it in the Task are cleared.

Test 1: singleTask (Without Affinity)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// 1. Launch MainActivity:
MainActivity
// Stack content:
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 2. Launch StandardActivity
MainActivity -> StandardActivity
// Stack content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 3. Launch SingleTaskActivity
MainActivity -> StandardActivity -> SingleTaskActivity
// Stack content:
com.example.launchmodetest/.SingleTaskActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 4. Launch StandardActivity
MainActivity -> StandardActivity -> SingleTaskActivity -> StandardActivity
// Stack content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.SingleTaskActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 5. Launch SingleTaskActivity
MainActivity -> StandardActivity -> SingleTaskActivity -> StandardActivity -> SingleTaskActivity
// Stack content:
com.example.launchmodetest/.SingleTaskActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

// Note: SingleTaskActivity receives am_new_intent and clears the StandardActivity above it

Test 2: singleTask (With Affinity)

When android:taskAffinity="" is set in the Manifest, launching a singleTask Activity creates a new Task.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 1. Launch MainActivity
MainActivity

// Stack 0 content:
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 2. Launch StandardActivity
MainActivity -> StandardActivity

// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 3. Launch SingleTaskWithAffinity
MainActivity -> StandardActivity -> SingleTaskWithAffinity

// Stack 1 content:
com.example.launchmodetest/.SingleTaskWithAffinity
// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 4. Launch StandardActivity
MainActivity -> StandardActivity -> SingleTaskWithAffinity -> StandardActivity

// Stack 1 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.SingleTaskWithAffinity
// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 5. Launch SingleTaskWithAffinity
MainActivity -> StandardActivity -> SingleTaskWithAffinity -> StandardActivity -> SingleTaskWithAffinity

// Stack 1 content:
com.example.launchmodetest/.SingleTaskWithAffinity
// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------

Summary

  1. Compared to singleTask, singleTaskWithAffinity creates a new Stack.
  2. Launching a StandardActivity from singleTaskWithAffinity places that StandardActivity in the same stack as singleTaskWithAffinity.
  3. Launching singleTaskWithAffinity again from Stack 0 does not create a new Task.
  4. singleTaskWithAffinity appears in the multi-task overview.

singleInstance Mode

1
android:launchMode="singleInstance"

As the name suggests, singleInstance creates a unique Task for the Activity when it’s first launched, no matter where it’s launched from. Subsequent launches will not create new instances unless the original is destroyed.

Test 1: singleInstance (Without Affinity)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
taskAffinity=com.example.launchmodetest

// 1. Launch MainActivity
MainActivity

// Stack 0 content
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 2. Launch StandardActivity
MainActivity -> StandardActivity

// Stack 0 content
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 3. Launch SingleInstanceActivity
MainActivity -> StandardActivity -> SingleInstanceActivity

// Stack 1 content (no Task in multi-task overview)
com.example.launchmodetest/.SingleInstanceActivity
// Stack 0 content
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 4. Launch StandardActivity
MainActivity -> StandardActivity -> SingleInstanceActivity -> StandardActivity

// Stack 1 content (no Task in multi-task overview)
com.example.launchmodetest/.SingleInstanceActivity
// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 5. Launch SingleInstanceActivity
MainActivity -> StandardActivity -> SingleInstanceActivity -> StandardActivity -> SingleInstanceActivity

// Stack 1 content: (no Task in multi-task overview)
com.example.launchmodetest/.SingleInstanceActivity
// Stack 0 content
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 6. Launch StandardActivity
MainActivity -> StandardActivity -> SingleInstanceActivity -> StandardActivity -> SingleInstanceActivity -> StandardActivity

// Stack 1 content: (no Task in multi-task overview)
com.example.launchmodetest/.SingleInstanceActivity
// Stack 0 content
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 7. Launch SingleInstanceActivity
MainActivity -> StandardActivity -> SingleInstanceActivity -> StandardActivity -> SingleInstanceActivity -> StandardActivity -> SingleInstanceActivity

// Stack 1 content (no Task in multi-task overview)
com.example.launchmodetest/.SingleInstanceActivity
// Stack 0 content
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

Summary 1

  1. SingleInstanceActivity creates a new Task, but this Task does not appear in the multi-task overview.
  2. SingleInstanceActivity is globally unique. If reused, its onNewIntent is called.
  3. Launching a new Activity from SingleInstanceActivity does not place it in the current Task; instead, it returns to the previous Task.

Test 2: singleInstance (With Affinity)

When android:taskAffinity="" is set in the Manifest, the SingleInstanceActivity does appear in the multi-task overview. All other behaviors remain the same as without affinity.

1
2
taskAffinity=null

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 1. Launch MainActivity
MainActivity

// Stack 0 content:
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 2. Launch StandardActivity
MainActivity -> StandardActivity

// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 3. Launch SingleInstanceWithAffinityActivity
MainActivity -> StandardActivity -> SingleInstanceWithAffinityActivity

// Stack 1 content: (Task appears in multi-task overview)
com.example.launchmodetest/.SingleInstanceWithAffinityActivity

// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 4. Launch StandardActivity
MainActivity -> StandardActivity -> SingleInstanceWithAffinityActivity -> StandardActivity

// Stack 1 content: (Task appears in multi-task overview)
com.example.launchmodetest/.SingleInstanceWithAffinityActivity

// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 5. Launch SingleInstanceWithAffinityActivity
MainActivity -> StandardActivity -> SingleInstanceWithAffinityActivity -> StandardActivity -> SingleInstanceWithAffinityActivity

// Stack 1 content: (Task appears in multi-task overview)
com.example.launchmodetest/.SingleInstanceWithAffinityActivity

// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 6. Launch StandardActivity
MainActivity -> StandardActivity -> SingleInstanceWithAffinityActivity -> StandardActivity -> SingleInstanceWithAffinityActivity -> StandardActivity

// Stack 1 content: (Task appears in multi-task overview)
com.example.launchmodetest/.SingleInstanceWithAffinityActivity
// Stack 0 content
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

-------------------------------------------------------------------
// 7. Launch SingleInstanceWithAffinityActivity
MainActivity -> StandardActivity -> SingleInstanceWithAffinityActivity -> StandardActivity -> SingleInstanceWithAffinityActivity -> StandardActivity -> SingleInstanceWithAffinityActivity

// Stack 1 content: (Task appears in multi-task overview)
com.example.launchmodetest/.SingleInstanceWithAffinityActivity
// Stack 0 content:
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.StandardActivity
com.example.launchmodetest/.MainActivity

Key Concepts

TaskAffinity

1
taskAffinity=null

The Task that an Activity has an affinity for. Conceptually, Activities with the same affinity belong to the same Task (from the user’s perspective, they belong to the same “application”). A Task’s affinity is determined by the affinity of its root Activity.

Affinity determines two things:

  1. The parent Task that an Activity will move to (see the allowTaskReparenting attribute).
  2. The Task that will host an Activity launched with the FLAG_ACTIVITY_NEW_TASK flag.

By default, all Activities in an application share the same affinity. You can set this property to group them differently, or even place Activities defined in different applications within the same Task. To specify that an Activity has no affinity with any Task, set it to an empty string.

If this attribute is not set, the Activity inherits the affinity set for the application (see the taskAffinity attribute of the <application> element). The default affinity name for an application is the package name set by the <manifest> element.

Relationship Between ActivityRecord, TaskRecord, and ActivityStack

  1. An ActivityRecord corresponds to an Activity instance and stores all information about that Activity. However, a single Activity may have multiple ActivityRecords because it can be launched multiple times, depending primarily on its launch mode.
  2. A TaskRecord consists of one or more ActivityRecords. This is what we commonly call a “task stack,” following a Last-In-First-Out (LIFO) structure.
  3. An ActivityStack manages TaskRecords and contains multiple TaskRecords.


(From http://gityuan.com/2017/06/11/activity_record/)

  1. Generally, without split-screen or virtual display functionality, both ActivityStackSupervisor and ActivityDisplay are unique to the system.
  2. ActivityDisplay primarily consists of three stacks: Home Stack, App Stack, and Recents Stack.
  3. Each ActivityStack can contain several TaskRecord objects.
  4. Each TaskRecord contains several ActivityRecord objects.
  5. Each ActivityRecord records information about one Activity.

Below is an example dump showing the current phone’s ActivityRecord, TaskRecord, and ActivityStack:
(adb shell dumpsys activity containers)

Activity Types

1
2
3
4
5
6
7
8
9
10
/** Activity type is currently not defined. */
public static final int ACTIVITY_TYPE_UNDEFINED = 0;
/** Standard activity type. Nothing special about the activity... */
public static final int ACTIVITY_TYPE_STANDARD = 1;
/** Home/Launcher activity type. */
public static final int ACTIVITY_TYPE_HOME = 2;
/** Recents/Overview activity type. There is only one activity with this type in the system. */
public static final int ACTIVITY_TYPE_RECENTS = 3;
/** Assistant activity type. */
public static final int ACTIVITY_TYPE_ASSISTANT = 4;

If you found this article helpful, feel free to share it on social media. I hope it helps others!

About Me && Blog

Below is my personal introduction and related links. I look forward to exchanging ideas with fellow developers—when three walk together, one is bound to be my teacher!

  1. Blogger’s Personal Introduction: Contains my WeChat and WeChat group links.
  2. Blog Content Navigation: A navigation guide to the content of this blog.
  3. Personally Curated and Collected Excellent Blog Posts - Must-Know Android Performance Optimization: Welcome to recommend or self-recommend (via WeChat private message).
  4. Android Performance Optimization Knowledge Planet: Welcome to join, thank you for your support!

One can walk faster alone, but a group can walk farther.

WeChat QR Code

CATALOG
  1. 1. standard Mode
  2. 2. singleTop Mode
  3. 3. singleTask Mode
    1. 3.1. Summary
  4. 4. singleInstance Mode
    1. 4.1. Summary 1
  5. 5. Key Concepts
    1. 5.1. TaskAffinity
    2. 5.2. Relationship Between ActivityRecord, TaskRecord, and ActivityStack
    3. 5.3. Activity Types
  6. 6. About Me && Blog