A task is a collection of activities that a user interacts with when using an app. Activities are stacked in the back stack in the order in which they are opened. In this topic, you will learn more about tasks and the back stack. You'll find out what launch modes are and how to use Intent flags when developing your applications.
Tasks and back stack
If you click the "Recently opened" button on your phone, you will see a list of tasks:
The activities in a task are arranged in a stack (known as the back stack). You can see a visualization of this below:
Let's take the Settings app as an example. A new task will be created when you open it, and the main settings activity will be shown on the screen and added (pushed) to the task's stack. Then, if you click on any item in the settings list, a new activity will be created, shown, and pushed to the stack. Pressing the "Back" button will destroy that activity and remove (pop) it from the stack. Clicking the "Back" button again will pop the previous activity off. And once all activities are popped off the stack, you will be returned to the Home screen, and the task will no longer exist. This is the stack's standard behavior. It's known as "last in, first out" and results in the most recent activity being shown on the screen. It's a launch mode that works well for most apps.
Here is a diagram of the example described above:
If a user hits the "Home" button without closing activities, the associated task will be backgrounded. It should then be possible to return to this task later with no changes in the back stack. However, if the user has many tasks (or apps) in the background, the system might kill some of them to recover resources, leading to the loss of unsaved data. Therefore it is the developer's responsibility to ensure that important data is saved.
Launch modes
There are four activity launch modes available: standard, singleTop, singleTask and singleInstance. They are defined in the AndroidManifest.xml file in the activity tag:
<manifest xmlns:android="<http://schemas.android.com/apk/res/android>"
package="com.hyperskill.tasks">
<application ...> <!-- skipped some attributes -->
<activity
android:name=".SecondActivity"
android:launchMode="standard" />
<activity ...>
<!-- intent-filter etc -->
</activity>
</application>
</manifest>
We covered the standard mode in the previous section, so let's summarize it and find out about the others!
standard
-
The default launch mode. The system creates a new activity and routes an Intent to it. The activity is pushed on top of the stack, even if the same activity is already foregrounded.
singleTop
-
This mode behaves differently from
standardif the activity you would like to start is already on the top of the stack. Instead of creating it again, the system routes an Intent to the existing instance through a call to theonNewIntent()method.
Example: The stack consists of three activities (A-B-C). C is at the top of the stack with its launch mode set tosingleTop. In this scenario, if you try to open activity C again, the stack will remain the same (A-B-C), and theonNewIntent()method will be called. However, if the activities were ordered differently to start with (A-C-B), calling activity C again would change the stack (A-C-B-C), as you can see below.
singleTask
-
Be careful with this launch mode because its behavior seems strange to most users. Only one instance of an activity with this launch mode can exist at a time. So, if this activity doesn't already exist in the task, it will be created and pushed to the top of the stack (in the same way as with
standardmode). But if it does exist, all activities placed higher in the stack will be immediately destroyed, revealing the one that has been called and firing anonNewIntent()method.
Example: Four activities have already been pushed to the stack (A-B-C-D), and activity B has been assigned thesingleTasklaunch mode. As shown below, calling activity B will pop activities C and D off the stack, leaving only A and B.The official documentation for Android developers describes this mode's behavior differently: "The system creates a new task and instantiates the activity at the root of the new task." "Root" here is a first item (activity) in the task. The
taskAffinityattribute is used to specify which task an activity prefers to belong to, and its default value is essentially just the package name of your app. You can change thetaskAffinityin the relevant<activity />tag, which is located in the AndroidManifest.xml file. However, the behavior described in the documentation only applies when thetaskAffinityattribute is not set to the default value. And, after changingtaskAffinity,singleTaskwill behave exactly as the official documentation describes.
singleInstance
-
This mode is the same as
singleTask, except that an activity with this launch mode will always be the only member of the task. If asingleInstanceactivity launches another activity, it will be launched in a different task (Back Stack).
Example: The stack already contains twostandardactivities (A-B). Activity C is set tosingleInstance, so launching it creates a new task (A-B)(C), as you can see in the below diagram.
Intent flags
Making launch mode changes in the manifest file works well when you always need the same behavior, but they can't be made during runtime. Fortunately, Intent flags provide more flexibility.
For example, apps usually send interactive notifications: you click on them, and an activity pops up. If these notifications constantly repeat, it becomes really annoying to press the "Back" button a million times to close all the created activities. Intent flags can help us solve problems like this, so let's learn about some of them:
-
FLAG_ACTIVITY_SINGLE_TOPhas the same behavior as thesingleToplaunch mode. -
FLAG_ACTIVITY_NEW_TASKcreates a new instance of the activity in the task. The documentation says that this flag acts likesingleTask. -
FLAG_ACTIVITY_CLEAR_TOPlooks at whether the activity already exists in the stack. If it does, it destroys every activity above, which results in the activity being at the top of the stack. If it doesn't already exist, it creates the activity in the usual way. Using this flag withFLAG_ACTIVITY_NEW_TASKwill result in similar behavior to thesingleTasklaunch mode, but the activity will be restarted. To avoid restarting and losing the activity state, use thesingleTasklaunch mode in the manifest file. -
FLAG_ACTIVITY_CLEAR_TASKclears the stack and places the freshly opened activity at the root of the stack. It's used withFLAG_ACTIVITY_NEW_TASK. -
FLAG_ACTIVITY_REORDER_TO_FRONTreorders the opened activity to the front. For example, if the initial stack order was A-B-C-D and activity A was called with this flag, the new order of the stack would be B-C-D-A. -
FLAG_ACTIVITY_NO_HISTORYprevents the activity from being kept in the stack.
You can find descriptions of more flags in the official documentation. Try them out — they can really help with app development!
Once you've decided which flags you want to use, you need to add them to your existing Intent. This can be done in the following way:
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
//in case you want to replace previous flags (if there are any) instead of adding them:
val intent = Intent(this, SecondActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)
Or, when you need more than one flag:
val intent = Intent(this, SecondActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
startActivity(intent)
//in case you want to replace previous flags (if there are any) instead of adding them:
val intent = Intent(this, SecondActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(intent)Conclusion
You now know what tasks are and how the back stack works. You also learned about the different activity launch modes and how to use Intent flags when you need to change launch mode behavior during runtime. Time for some practice!