A task is the stack ("Last in, First out")
which contains a collection of activity instances. Normally, when a
user starts an app a new task will be created, and the first activity
instance is called as a root of the task. The Android system can hold
multiple tasks at the same time and only one task is in the foreground.
Similar to a double click of the home key on iOS, if you long press the
HOME key on Android you'll be presented with a list of your currently
running applications. You can select any one of these applications
(which are currently running in the background) in order to bring it to
the foreground and interact with the app! Of course, because background
tasks do tend to use up your processor cycles you should try to keep
your backgrounded apps to a minimum to ensure your phone performs
optimally.
Now let's look at the launch mode of an activity. Launch mode allows
you to define how a new instance or the existing instance of an activity
is associated with the current task. The activity launch mode has four
valid values:
|
<activity android:launchMode = ["standard" | "singleTop" | "singleTask" | "singleInstance"] ../>
|
The 'standard' is the default value. The four values fall into two groups:
- 'standard' and 'singleTop' can instantiate multiple activity instances and the instance will stay in the same task.
- For 'singleTask' or 'singleInstance', the activity class uses the
singleton pattern, and that instance will be the root activity of a new
task. Let's examine each value:
"standard":
Multiple instances of the activity class can be instantiated and
multiple instances can be added to the same task or different tasks.
This is the common mode for most of the activities.
"singleTop":
The difference from 'standard' is, if an instance of activity already
exists at the top of the current task and system routes intent to this
activity, no new instance will be created because it will fire off an
onNewIntent() method instead of creating a new object. Let's take the
Twitter-oauth integration as example. Suppose we have the following
NewsDetailActivity declared:
1
2
3
4
5
6
7
8
|
<activity android:name=".NewsDetailActivity" android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:scheme="oauth" android:host="twitt"></data>
</intent-filter>
</activity>
|
So if a user goes to this activity in the current task (let's say
Task #1), a new instance of NewsDetailActivity will be pushed to the
top. Now start the oAuth process and the Android system routes the
intent to the default Android Browser application, whose launch mode is
'singleTask'; that means a new Task begins for the browser activity,
let's say Task #2. Hence the 'NewDetailActivity' is still on top of the
Task #1.
After the user finishes the authorization on Twitter's page, the
customized callback url 'oauth://twitter' will be invoked. Because
NewsDetailActivity declares support for that data type, the system
routes the intent to the 'NewsDetailActivity'. Since
NewsDetailActivity's launch mode is 'singleTop', and the top instance on
Task #1 will be reused, its onNewIntent() method will be invoked to
continue oAuth's last step. Here is the code for that:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Uri uri = intent.getData();
if (uri != null && uri.toString().startsWith(CALLBACK_URL)) {
String verifier = uri.getQueryParameter("oauth_verifier");
try {
//load other persisted data goes here
....
//get the request-token from prefs and request the access token
TwitterFactory twitter = new TwitterFactory().getInstance();
requestToken = prefsManager.getRequestToken();
prefsManager.clearTwitterRequestToken();
twitter4j.auth.AccessToken accessToken = twitter.getOAuthAccessToken(requestToken, verifier);
// save the access token
prefsManager.saveTwitterOauth(accessToken.getToken(), accessToken.getTokenSecret(), accessToken
.getScreenName());
//other logics to do the post to twitter
....
} catch (Exception e) {
Log.e(TAG, e.getMessage(), e);
}
}
}
|
"singleTask":
A new task will always be created and a new instance will be pushed to
the task as the root one. However, if any activity instance exists in
any tasks, the system routes the intent to that activity instance
through the onNewIntent() method call. In this mode, activity instances
can be pushed to the same task. And if the user clicks the BACK key
from the singleTask activity, the system will return the user to the
previous activity.
This mode is useful for activities that act as the entry points. For
example, in a tab-based Twitter client, we can declare the main
TabActivity as singleTask. This is also useful if you only want a single
instance of the activity to be created. One example of singleTask is
the Browser application. Let's take a Twitter-client-application as
example, where the main activity is a TabActivity and has three tabs:
tweets, replies and messages. And we want to suppose auto-refresh and
notification function when app is running.
In AndroidManifest.xml, we have:
1
2
|
<activity android:name=".MainTabActivity" android:launchMode="singleTask" android:alwaysRetainTaskState="true" android:windowSoftInputMode="adjustPan">
</activity>
|
Suppose we have the notification for new tweet/replies/messages, and we
hope that clickong on the notification will take the user to the current
TabActivity, and switch to corresponding tabs. (Here we suppose the app
is not closed before user clicks the notification). Because the
MainTabActivity's launch mode is singleTask, system routes the intent
to the MainTabActivity by calling its onNewIntent() method. And in this
method, we can determine which tab to switch to according to the bundle
data in the intent.
"singleInstance":
Same as 'singleTask', except that the no activities instance can be
pushed into the same task of the singleInstance's. That means, the
activity with launch mode is always in a single activity instance task.
This is a very specialized mode and should only be used in the
applications that are implemented entirely as one activity.
The activity launch mode has four valid values.
ReplyDeleteExcess Flow Check Valve