The Activity launch mode is a common interview question, but one that many developers fail to answer in interviews.

Most developers are familiar with the four properties of LaunchMode, but the effect of the Activity LaunchMode in different scenarios is not covered by just four properties.

In this article, we’ll take a look at the Activity launch mode known as the “interview black hole.”

What exactly is a Task?

In the Android system bar, there are three function keys: Back (return), Home (display desktop) and Menu (open Task view).

When we press the Menu button, we will move the currently displayed Activity from the foreground to the background, open the Task view, and display all existing Activity stacks in the system (Activity stacks are tasks).

A Task is also called a Task stack and a return stack, which are defined in different ways, but are essentially the same thing.

As Android developers, we all know that activities launched in an App are added to tasks to manage them. However, many developers mistakenly assume that tasks belong to App management and that what is displayed in the Task view is actually the App.

This is wrong.

First, Tasks are managed by the Android system. Task does not have the concept of thread or process, it does not belong to App, it is only the Android system used to manage activities that have been started.

A Task is essentially a collection of activities. Tasks manage the activities in the stack according to its data structure. If the Task is in the foreground, the Activity at the bottom of the Task (equivalent to the top of the stack) is displayed on the interface and executes the corresponding lifecycle function.

Second, tasks presented in the Task view are categorized by Affinity. That is, the Affinity of tasks shown in the Task view is different.

About starting an Activity

In the App, all activities of an Activity can be divided into two types:

  • New (Activity launch mode only works for this behavior)
  • restore

In an App, most of the Activity behavior is new (start the Activity with the startActivity function, for example: direct call, click notification, and so on). Therefore, we only need to know the common recovery behavior to distinguish between all the common activities in the App.

The most common recovery action is to return to the previous Activity in the current Task using the Back key. When the Back key is pressed, the Activity currently at the bottom of the Task is removed from the Task and destroyed. At this point, the previous Activity is repositioned at the bottom of the Task and displayed on the screen.

Click the Task in the Task view to make the corresponding Task return to the foreground, and the Activity at the bottom of the Task is displayed on the screen. This is usually an act of recovery.

Why is it usually? Not all tasks displayed in the Task view are alive. When the user repeatedly returns to the previous Activity by clicking the Back button, clicking the Back button will return the Task to the desktop when there are no other activities in the Task, and the empty Task will be destroyed.

But if YOU click the Menu button to open the Task view, you will find that the destroyed Task is still in the Task view. Why?

The Task is a recently used record. When the user clicks on the Task again, the App corresponding to the Task’s Affinity value is restarted.

Similarly, clicking the App icon to start an Activity in a Launcher might be a recovery action.

Whether starting an Activity by clicking the App icon is a recovery action depends on whether the Task corresponding to the Affinity value of the App being started is alive. If the corresponding Task is alive, the Task is returned to the foreground and the Activity at the bottom of the Task is displayed, which is a recovery behavior. If the Task has been destroyed, restart the App corresponding to the Task, which is a new behavior.

What is Affinity?

Affinity translates to Affinity and is used to indicate which Task an Activity prefers to store itself in. This can be declared in the AndroidManifest file via the Android :taskAffinity attribute.

By default, if the Activity is not actively declared via the Android :taskAffinity attribute, the Activity defaults to the package name of the current application as its android:taskAffinity attribute value.

Conceptually, activities with the same Affinity should belong to the same Task (they don’t have to); From the user’s point of view, it should belong to the same App.

Because each Affinity has a separate list item in the Task view, it looks like a separate App. In fact, an Activity in a list item can come from several different apps.

The Affinity value of a Task is determined by the first Activity added (the Activity at the bottom of the stack) and does not change.

Activity Start mode

The Activity startup mode is a very complicated difficulty, which determines the association between the Activity to be started and the Task, and directly affects the intuitive feeling of users.

The Activity startup mode can be defined in two ways:

  • Set the Activity in the androidmanifest.xml fileandroid:launchModeAttribute values.
  • When callingstartActivity(Intent)When the function starts the Activity, theIntentAdd or set flag bits.

However, in actual business scenarios, LaunchMode and Intent flags need to be used together, and multiple application interactions need to be considered, which can become more complicated.

Its complexity and difficulty mainly lies in:

  • Activities stored in tasks may come from different apps; An App can also contain multiple tasks.
  • Tasks can be stacked.
  • Activities that are already in one Task can be migrated to another Task.
  • The attribute value of an Intent Flag can be used in multiple combinations.

Some launch modes can be defined with LaunchMode, but not with Intent Flag. Also, some launch modes can be defined with Intent Flags that cannot be defined in LaunchMode. The Intent flags complement each other, but cannot completely replace each other, and the Intent flag has a higher priority.

LaunchMode

LaunchMode is statically defined in the Androidmanifest.xml file with only four attribute values:

  • Standard Mode
  • Top of Stack Reuse Mode (singleTop)
  • Global singleTask
  • singleInstance

Standard Mode

Standard is the default for LaunchMode. If we do not actively set the Android :launchMode attribute for our Activity in the Androidmanifest.xml file, the Activity’s Android :launchMode attribute defaults to standard.

Each time an Activity is started, a new instance of the Activity is created and added to the Task of the initiator.

Top of Stack Reuse Mode (singleTop)

If the Activity instance is already at the bottom of the launcher’s Task (top of the stack), the Activity instance is reused and its onNewIntent function is called back. Otherwise, create a new Activity instance and add it to the Task of the initiator.

Global singleTask

Effects of singleTask: When an Activity is started, if the Activity instance is already in the Task to which Affinity corresponds, it reuses the instance already in the Task, calling the onNewIntent function of that instance, And remove all Activity instances above this instance; Otherwise, create a new Activity instance and add it to the Task corresponding to the Affinity.

The effects of Standard and singleTop were described based on the Task of the initiator. What if an Activity with standard/singleTop is assigned a different Affinity than the Task on which the initiator is based?

Result: nothing will change! An Activity with Standard/singleTop is still associated only with the Task of the initiator. In other words, Affinity has no effect on activities that have Standard/singleTop set.

An Activity with a singleTask set will only associate with the Task specified by Affinity.

For example, suppose Activity A and Activity B both have “singleTask” set. The Affinity of Activity A is com.example.test, and the Affinity of Activity B is com.example.test.other. Com.example. test starts Activity A by default. If you start Activity B again, a new Task with com.example.test.other will be created and the instance of Activity B will be added to the Task.

The Task of the stack

For the above example, there is one detail: When Activity B is started, the Task whose Affinity is com.example.test.other is stacked on top of the Task whose Affinity is com.example.test. If Activity A is also started in Activity B, the instance of Activity A in the Task whose Affinity is com.example.test is reused. Stack tasks whose Affinity is com.example.test on top of tasks whose Affinity is com.example.test.other.

When you start an Activity and need to switch to another Task, the system puts the target Task on top of the initiator’s Task, making it foreground. As described in the example.

If the user repeatedly exits by pressing the Back key, the animation of switching tasks is obvious. When the user repeatedly clicks the Back button to exit, the activities are removed from the top Task. When there is no Activity in the uppermost Task, it is destroyed and moved out of the Activity in the next Task.

As mentioned earlier, the list items presented in the Task view are categorized by Affinity. When we open the Task view by clicking the Menu key, all tasks are moved to the background and displayed by Affinity.

That is, when the Task view is opened, all stacked tasks are split.

singleInstance

If the Activity instance already exists (regardless of which Task it is in), the onNewIntent function is called back. Otherwise, create a new target Task and an Activity instance, and add the new Activity instance to the new target Task.

And the target Task can only hold a single instance of the target Activity. If you start a new Activity in that Task, the Task for which the target Activity’s Affinity corresponds is pushed to the foreground.

SingleInstance is actually an “enhanced” version of singleTask. SingleTask requires that there be only one instance of its own Activity in the system (uniqueness), while singleInstance requires an exclusive Task (uniqueness + exclusivity) on top of singleTask.

Intent flag

When starting an Activity, we can change the default association between the Activity and its Task (LaunchMode) by setting one or more corresponding flags in the Intent passed to the startActivity(Intent) function. The priority of the Intent flag is higher than that of the LaunchMode.

Intent Flags have a number of Intent flags, four of which are commonly used:

  • Intent.FLAG_ACTIVITY_NEW_TASK
  • Intent.FLAG_ACTIVITY_CLEAR_TASK
  • Intent.FLAG_ACTIVITY_SINGLE_TOP
  • Intent.FLAG_ACTIVITY_CLEAR_TOP

Intent.FLAG_ACTIVITY_NEW_TASK

Intent.flag_activity_new_task should be the flag most developers will be familiar with, and one of the most common scenarios is for launching an Activity without an ActivityContext.

Intent.FLAG_ACTIVITY_NEW_TASK activates Affinity, which determines whether to switch tasks to start the target Activity.

As mentioned earlier, Affinity has no effect on activities with standard/singleTop Settings, but this only applies if there is no intent.flag_activity_new_task. Intent.flag_activity_new_task has no effect on an Activity with singleTask/singleInstance set.

Intent.flag_activity_new_task has slightly different effects on standard and singleTop, so we need to discuss it by type.

With Standard, tasks are switched to start the target Activity when the Affinity of the target Activity is inconsistent with that of the initiator’s Task.

With singleTop, it adds a restriction to Standard, Tasks are switched to start the target Activity only if the instance of the target Activity is not at the bottom of the initiator’s Task (top of the stack) and the Affinity of the target Activity is inconsistent with that of the initiator’s Task.

Only the conditions of whether to switch tasks are analyzed here. The logic of whether to create new target Activity instances and whether to reuse existing instances after switching or not will be too complicated, and these conditions can be tested when they need to be used.

Intent.FLAG_ACTIVITY_CLEAR_TASK

Intent.flag_activity_clear_task specifies that this flag must be used in combination with intent.flag_activity_new_task.

This flag causes any existing tasks associated with the Activity to be cleared before it starts. That is, the Activity will become the new root for other empty tasks, and all old activities will be removed. This can only be used with FLAG_ACTIVITY_NEW_TASK.

Intent.flag_activity_clear_task has no effect by itself. Use it in conjunction with intent.flag_activity_new_task.

Intent.FLAG_ACTIVITY_CLEAR_TASK + Intent.FLAG_ACTIVITY_NEW_TASK removes all activities from the target Task if the target Task exists. Then add a new target Activity instance to the target Task. If the target Task does not exist, create a new target Task and an Activity instance, and add the new Activity instance to the new target Task.

Intent.flag_activity_clear_task + Intent.flag_activity_new_task, the user will see the Task switch animation.

Intent.flag_activity_clear_task has a high priority and can ignore virtually all configurations, including other launchmodes and Intent flags. Even the Task of the Activity with singleInstance set is cleared and the target Activity is rebuilt.

Intent.FLAG_ACTIVITY_SINGLE_TOP

Intent.flag_activity_single_top forces the Activity’s LaunchMode to override singleTop.

FLAG_ACTIVITY_SINGLE_TOP = intent.flag_activitY_singLE_TOP = intent.flag_activity_single_TOP = intent.flag_activity_single_TOP = intent.flag_activity_single_TOP Regardless of the value of the Android :launchMode attribute that the Activity sets in the Androidmanifest.xml file (because the Intent Flag takes precedence over the launchMode attribute).

Intent.FLAG_ACTIVITY_CLEAR_TOP

Intent.flag_activity_clear_top clears all other Activity instances above the target Activity instance (including its own instance). Then re-create a target Activity instance and add it to the target Task.

Intents.FLAG_ACTIVITY_NEW_TASK + intents.FLAG_ACTIVITY_SINGLE_TOP + intents LaunchMode is forced to override singleTask.

Intents.FLAG_ACTIVITY_NEW_TASK + Intents.FLAG_ACTIVITY_SINGLE_TOP + intents.FLAG_ACTIVITY_CLEAR_TOP The behavior pattern becomes consistent with that of the Activity with the singleTask set.

Application scenarios

Only the four LaunchMode attribute values are discussed here. Since Intent flags are often added to dynamically modify the behavior logic of LaunchMode, this needs to be analyzed based on actual business requirements. The general scenario is discussed here.

LaunchMode Application scenarios
Standard (default) Regular Activity
singleTop Suitable for the same type of Activity. For example, the content display page started by receiving Notification, the return page for time-consuming operations, and the login page
singleTask Suitable for activities that can be used as entry points to programs. For example: WebView page, scan page, confirm order interface, payment interface and so on
singleInstance Suitable for activities that need to be separated from programs. For example, the alarm screen, call screen, and lock screen are displayed

conclusion

This article reviews some concepts in the Activity LaunchMode and introduces the basic LaunchMode attribute values and several common Intent flags.

The actual use of the Activity LaunchMode involves various combinations of LaunchMode and Intent flag. The actual effect cannot be explained in a single article, but can only be understood by people trying to use it in practice.

reference

Android Interview Black hole – What happens when I press the Home button and cut back?

Talk about the startup mode of your Activity

The Android interviewer failed: the Activity launch mode

Android interview: Tell me about the four startup modes of Android