Before API 11, we used activities show every new page on the screen. Now with Fragments and the navigation tools in API 28, it’s totally possible to make a very complex app with only one activity. However, activities are still great for sectioning your app out into stages and processes. Maybe you want to divide up all the marketing into one activity, and have the actual app in its own activity. Maybe you want one section reserved for a feature, like a chat service. Knowing the activity launch modes helps you better divide these processes in ways that makes sense to your users. Sitting at work, I could never remember the launch modes off the top of my head, so I thought I would write a blog about it, animate some gifs to illustrate the concepts, and then share it with everyone. Enjoy!

Before talking about launch modes, lets first understand the role of a task. A task holds a collection of activities that are arranged in a stack called the backstack. The first activity to be launched in a task is the root activity. Pressing the back button on a root activity not only kills the activity, but it kills the task, and possibly the app.

Now let’s dive into some launch modes!

Let’s say you have a task with a root activity called Activity A, and then launch a new activity called B, B gets pushed to the top of the stack. Now let’s say you launch another Activity B from the B we just created, you will now have two instances of Activity B stacked on top of one another. If a user presses the back button, they will go back to another instance of Activity B. This could be very confusing to the user. The stacking and creation of activities on top of each other, no matter what, is called the Standard launch mode. If there is no launch mode defined in the activity XML in the manifest, the activity will use the standard launch mode.

Now that we see how Standard mode can be jarring to the user, we can now understand the Single Top launch mode. This launch mode stops different instances of the same activities from being stacked on top of one another. Let’s say Activity B is a single top. We can define launch modes in the manifest like this:

///AndroidManifest.xml

<application

...>

<activity android:name=".Activity_A">

<intent-filter>

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

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

</intent-filter>

</activity> <activity android:name=".Activity_B" android:launchMode="singleTop"/> <activity android:name=".Activity_C"/>

<activity android:name=".Activity_D"/>

</application>

So now if you launch Activity B from Activity B, instead of creating a new instance of B and stacking it on top of the old B, the intent is passed into the current instance of B. The only way to have two instances of the same activity in one task is to launch a different activity from B, and then create B from that activity. The main concept of the single top launch mode is that you can not have two instances of the same activity stacked on top of one another.

If you don’t want 2 instances of the same single top activity in a task while using single top launch mode, you can pass the FLAG_ACTIVITY_CLEAR_TOP constant in your intent. To illustrate what this does, let’s say your activity stack is ABC (B is still single top). If you launch B from C with FLAG_ACTIVITY_CLEAR_TOP, your stack will pop all the way down to B and the intent will be passed to that very instance of B.

// code example for passing the constant flag in your intent Intent intent = new Intent(this, Activity_B.class);

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

startActivity(intent);

The next launch mode is called Single Task. In this launch mode, we state that an activity can only belong to one task throughout all tasks in the app. So similar to the FLAG_ACTIVITY_CLEAR_TOP behavior, if your stack is ABC, and you launch B (a single task) from C, we pop all the way down to B, and pass the intent to that instance.

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

But what if we want B to be in its own task? This is where task affinity comes into play. Task affinity lets you define which task an activity belongs to. By default, an activity has the same task affinity as its root activity. With task affinity, we can now separate activities into different tasks.

<activity android:name=".Activity_A"

android:taskAffinity="com.affinity.of.a">

<intent-filter>

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

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

</intent-filter>

</activity> <activity android:name=".Activity_B"

android:launchMode="singleTask"

android:taskAffinity="com.affinity.of.b"

/>

Here, Activity A and Activity B have different task affinities. When A is created in Task 1, C is launched from A. By default, each activity has the same affinity as its root, so we are still in Task 1. Now B is launched from C. B has a different task affinity, so it is now the root of Task 2, which then moves to the foreground. If we launch a new instance of Activity C from B, C belongs to Task 2 because that is the task affinity of the root activity (in this case, B). But what if we now try to launch A from C in Task 2? Since A‘s affinity is Task 1, we shift from Task 2 to Task 1, pop all the way back to Activity A, and finally pass the intent to A.

Knowing Single Task will help us better understand the final launch mode; Single Instance. Like Single Task, an Activity with Single Instance can be the only Activity across all tasks. The difference between the two is that an Activity with Single Instance can also be the only activity in a task.

<activity android:name=".Activity_B"

android:launchMode="singleInstance"

android:taskAffinity="com.affinity.of.b"

/>

In this example, Activity B will have a launch mode of Single Instance. Activity A in Task 1 launches Activity B. This makes Activity B launch in a new task, which is then put in the foreground. Activity B then launches Activity C. Since a Single Instance can be the only activity in a task, C is launched on top of Activity A in Task 1, and then Task 1 comes to the foreground.

Task affinity also plays a role in Single Instance. If Activity B has no task affinity, a user can not navigate back to Task 1. If B did have task affinity, a user will be able to go back and forth between Task 1 and 2.

Knowing about launch modes helps me make better UI/UX experiences for my users, and even helps me solve some head-scratching bugs, so I hope this information helps you too!

I want to give a shoutout to Anil Deshpande’s CodeTutor youtube page for helping me understand the concept better. Here is the first of seven videos on this subject: https://www.youtube.com/watch?v=m8sf0UkJkxo