The previous post of the Activities and Tasks series gave an introduction to the concepts behind activities and tasks. We have seen that activities correspond to visible screens in the UI, that activities are grouped as stacks within tasks, and tasks are sent to the background and foreground as atomic units. In this post of the series, we focus on Android’s intent concept and address the following questions:
- What are intents?
- How do we use them to launch activities?
- What options (flags) does Android provide to customize this launch? (e.g. in terms of target task or activity instance creation)
In order to ease understanding of intents and their various flags, akquinet Modular and Mobile Solutions provides an Android application to experiment with intent flags. With it, you can start different types of activities, specifying the intent flags you want to pass, and examine the effects. Install it by pointing your Android browser to this URL.
Intents and activity launching
An intent is a data structure containing a description of a to-be-performed operation. This operation primarily consists of an action and of data to operate on, although there are various optional parameters to describe the operation in more detail. Technically speaking, this action is just a constant, either a pre-defined one from Android, like ACTION_VIEW or ACTION_EDIT, or a custom one that we can define ourselves.
An intent is always handled by an Android component, namely an activity, a service or a broadcast receiver. In this blog post series, we will focus on activities as intent handlers. For our purposes, an intent is used to launch an activity.
To create an intent and launch an activity with it, we can write the following code within our caller activity:
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.akquinet.com/") startActivity(intent);
In this example, we give two parameters to the Intent constructor: The action to be performed (here view) and the corresponding data (here a web page URL). Then, we simply pass the Intent object to startActivity(Intent). Basically, what we do here is telling Android that we want to view the akquinet homepage. Android will look for activities capable of handling that intent, which in this case is a web browser activity, and start it. Note that any activity can be declared capable of handling certain intent types by defining intent filters in the application’s AndroidManifest.xml file.
Instead of letting Android choose a suitable activity, an intent may also name the to-be-launched target activity explicitly by specifying the target activity’s class, like so:
Intent intent = new Intent(this, MyActivity.class); startActivity(intent);
When run, this code snippet has the following consequences:
- A new instance of MyActivity is created
- The instance is pushed on top of the current task’s stack, which is the one the calling activity is in.
- The activity is started and brought to the foreground.
Customizing the launch of activities via intent flags
The described behavior can be modified by specifying intent flags on the intent instance before passing the intent to startActivity(Intent), for example:
This will bring an existing instance of the called activity type present in the current stack to the foreground (if there is such an instance) instead of creating a new instance. Android 2.0 defines various intent flags, which are now explained in more detail.
This flag is set by the system as an indication that an existing activity with launch mode singleTask has been called and reused. Activity launch modes are discussed in more detail in the next blog post.
This flag marks the called activity and all activities put on top of it to be cleared (removed from the stack) when the task is reset. This reset is performed as soon as the task is brought to the foreground using FLAG_ACTIVITY_RESET_TASK_IF_NEEDED, which is always set by the system when the user resumes a task from the home screen, the main menu or the list of recently started activites.
You can use this to define a point in the task stack from where all started activities should be “forgotten” once the task is sent to the background.
If there is already an instance of the called activity type present in the stack, then this instance is brought to the foreground instead of creating a new instance. Also, all activities in the stack that reside on top of that instance are cleared from the stack. For example, assuming that the current activity stack is ABCDE, launching an activity of type C will clear activities D and E from the task and result in the stack ABC.
Normally, when launching an activity in a new task, the target activity is shown in the list of recently launched activities (accessible via long press of the home button). For example, this is the case when launching the browser from your activity to render a web page. Using this flag, we can suppress that behavior, effectively excluding the target activity from the list of recently launched activities.
By default, in order for an activity B to be able to propagate a result back to the calling activity A, A has to use the method startActivityForResult(Intent) instead of method startActivity(Intent) to start B. When B defines its result via setResult(int resultCode) and finishes, the callback method onActivityResult() is called on A where the result can be retrieved.
Suppose now that B calls another activity C, which defines the result, and we want to forward that result back to A. In order to avoid having to pass results manually from B to A, Android provides this flag.
In our example, this means that B calls C, specifying the forward flag and using startActivity(Intent). C may then define a result, which is forwarded back to A automatically once C and B are finished. The callback method onActivityResult() is called on A but not called on the intermediate activity B as B only forwards the result instead of explicitly handling it.
Note that the flag may only be used in conjunction with startActivity(Intent), not with startActivityForResult(Intent), because an activity using the latter method marks the end of a forwarding chain and should handle the result in its callback method.
This flag is set by the system as an indication that an activity has been launched from the list of recently launched activities.
If this flag is used on its own (without FLAG_ACTIVITY_MULTIPLE_TASK), a new task is only created if there is not already a task present that the target activity has an affinity for (task affinities are examined more closely in the next blog post). If such a task already exists, the activity is put into that task instead of creating a new one.
As all activities specified within the same application have a default affinity to remain in the same task (this can be customized), starting an activity defined in the same application as the calling activity using this flag will not create a new task, unless FLAG_ACTIVITY_MULTIPLE_TASK is specified as well.
Introduced with Android 2.0, this flag disables the usual animation accompanied by an activity transition. For example, this can be used to call an activity that itself launches another activity without further user interaction, resulting in only one transition animation to be shown instead of two.
This flag implies that the called activity is not kept in the task’s stack. When navigating away, the user cannot return to it. For example, this is useful to launch activities that perform an immediate dispatch to another activity. This activity is consequently skipped if the user presses the back button as it is not kept in the stack.
This flag may be used as an indication that the activity transition is not an action directly performed by the user but rather an automatic one. For example, this is true for the call-in activity that is automatically launched when the device receives a phone call. Technically, it means that the invocation of callback method onUserLeaveHint() on the caller activity is suppressed.
If there is already an instance of the called activity type present in the task stack, that instance is brought to the foreground while the rest of the stack is kept intact. This effectively reorders the stack. For example, assuming that the current activity stack is ABCDEF, launching an activity of type C using this flag will result in the new stack ABDEFC.
This flag has no effect unless the intent creates a new task or brings an existing task to the foreground. In that case, the task is reset, meaning that task affinities are applied (resulting in activities being moved from or to this task) and that, given that FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET is set as well, the task is cleared according that flag’s specification.
If an instance of the target activity is already at the top of the stack, no new instance is created.
The akquinet Mobile and Modular Solutions provides an Android application to help you understand the effects of the intent flags. It lets you start exemplary activities using arbitrary intent flags and inspect the effects on the resulting task stack.
All described behavior not only depends on intent flags specified, but also on attributes defined on the called activity type (in AndroidManifest.xml), including task affinities and launch modes. While intent flags are specified by the caller, launch modes and affinities are properties of the callee. Those will be discussed in the next post of this series.