The Startup mode of Android is commonly used in our daily development, which is often asked in interviews. Although we are familiar with him, we may know some things too comprehensively, so write an article to summarize this knowledge. The main content of this article is from the book “The Art of Android Development”, which is available on the web at the end of the article.

Program source code

directory

  • 4. Start mode
  • What is a task stack
  • How does an Activity specify the desired task stack
  • TaskAffinity usage scenarios
  • The Activity of the Flags
  • Matching rule of IntentFilter
  • How do I determine whether implicit startup is successful

1. Four startup modes

Standard: indicates the standard startup mode

  • Every time an Activity is started, it is recreated, regardless of whether the instance exists.
<! <activity Android :name=".StandardActivity"/>
Copy the code

The following is taken from the bottom of page 16 of chapter 1 of The Art of Android Development

In Standard mode, whoever starts the Activity runs it in its task stack. For example, if ActivityA starts ActivityB(B is standard mode), ActivityB will be added to ActivityA’s task stack.

Do not pass an ApplicationContext when you start your Activity. Intent.setflags (intent.flag_activity_new_task); Otherwise return the following exception:

SingleTop: Top of stack reuse mode

  • The top of the newly started Activity stack already exists and will not be recreated, and the onNewIntent method will be called
  • If an Activity exists but is no longer on the top of the stack, it is recreated and the new Activity is pushed to the top of the stack.
<activity 
android:name=".SingleTopActivity"
android:launchMode="singleTop"/>
Copy the code

SingleTask: In-stack reuse mode

  • As long as the Activity exists in the stack, starting the Activity multiple times does not create new instances, and the system calls the onNewIntent method
  • If an Activity exists on the stack but is not at the top of the stack, the system pushes all activities above the Activity to the top of the stack.
<activity 
android:name=".SingleTaskActivity"
android:launchMode="singleTask" />
Copy the code

SingleInstance: single-instance mode

  • The Activity can only be in a single task stack
<activity 
android:name=".SingleInstanceActivity"
android:launchMode="singleInstance" >
Copy the code

Lifecycle execution:

  • In singleTask, singleInstance, singleInstance mode, if the Activity is started right at the top. Then his life cycle is executed as:
onPause-->onNewIntent-->onResume
Copy the code
  • In singleTask and singleInstance mode, if there is an Activity instance on the stack, but it is not at the top of the stack. Then the life cycle executes as follows
onNewIntent-->onRestart-->onStart
Copy the code

2. What is a task stack

To check activity status on the stack, type adb shell Dumpsys Activity activities on the console to quickly locate the package name by searching for the keyword most recent first

Task stack (Task) :

Task features:

  • The Android task stack is mainly used to store activities, following the principle of “first in, last out”.
  • The Android task stack is a collection of activities, and each time we open a new Activity or close an Activity, an Activity component is added or subtracted from the stack.
  • The task stack is destroyed when there is no Activity or the App exits.
  • An App has more than one task stack. Activities in the task stack can come from different apps, and activities in the same App can also be separated from the same task stack.

3. How does the Activity specify the desired task stack

The Activity specifies the stack of tasks to start by adding the taskAffinity attribute to the configuration file.

TaskAffinity features:

  • By default, the name of the task stack where the Activity starts is the application package name.
  • If you specify the value of this attribute, it cannot be the same as the package name; otherwise, it is equivalent to not specifying the value.
  • This is used in conjunction with the singleTask or allowTaskReparenting attributes in general and is not useful in other situations.
<activity android:name=".TestActivity"
android:launchMode="singleTask"
android:taskAffinity="com.test.singleTask.affinity"/>

<activity android:name=".Test2ActivityC" 
android:exported="true"
android:allowTaskReparenting="true"/>
Copy the code

4. TaskAffinity usage scenarios

The following paragraph is excerpted from the Activity startup mode and Task stack (Task) comprehensive and in-depth record (bottom).

TaskAffinity and singleTask application scenarios

If there is such a requirement, our client app is running in the background. At this time, we ask wechat to call a page of our client app due to some needs. After the user finishes relevant operations, we do not do any processing, and press Back or current activity.Finish (). The page will stay in its own client (at this time our app is not empty back stack), which is obviously not logical, and the user experience is quite problematic. Our requirement is that the rollback must go back to the wechat client, and ensure that you do not kill your app. Our solution is to set the current Activity property to: LaunchMode=””SingleTask” taskAffinity=”com.tencent. Mm “where com.tencent. In this way, the rollback will follow the principle of “The remaining activities in the Task must be rolled back as long as there are activities in the Task” and will not return to the client. It also does not affect the original Activity and Task logic of the client.

TaskAffinity and allowTaskReparenting application scenarios

An E-mail application message contains a link to a web page. Clicking on this link will launch an activity to display the page. Although the activity is defined by the browser application, the activity is loaded by the E-mail application. So at this point the activity also belongs to the E-mail task. If the E-mail app switches to the background, the next time the browser opens it will display the activity instead of the browser’s home screen because of its allowTaskReparenting value of true, and the ActVity will move from the E-mail task stack to the browser’s task stack. The activity will not be displayed the next time you open e-Bought.

Taskffinity and singleTask examples:

Note: if you use my project is built on making test this feature, please send TestTaskffinityOrAllowTaskRep. Zip this package decompression, and import the AS. This zip is a testTask app that I wrote while testing to jump to the androidreview app.

The testTask app (T app for short) has A button A in MainActivity. Clicking the button invokes the SingleTaskActivity of androidReview app (A app for short). Here is the main code for both applications.

TestTask application code

switch (v.getId()) {
    caseComponentName cnForSingleTask = new ComponentName("com.hdd.androidreview"."com.hdd.androidreview.Patterm.SingleTaskActivity");
    intent.setComponent(cnForSingleTask);
    startActivity(intent);
    break;
}
Copy the code

Androidreview app code:

<activity
    android:name=".Patterm.SingleTaskActivity"
    android:exported="true"
    android:launchMode="singleTask"
    android:taskAffinity="cmom.han.testbt.testTask">
</activity>
Copy the code

As you can see from the A application code configuration above, the taskAffinity property configudes the package name of the T application. So SingleTaskActivity will be created in T’s task. Suppose T applies the MainActivity button A to the event that starts SingleTaskActivity. Cmom.han.testbt. testTask will have SingleTaskActivity and MainActivity in the stack. Here is the Activity information on the stack.

TaskAffinity and allowTaskReparenting instances T application B button click event code:

caseR.i.mbnt_forallowtaskrep: //allowTaskReparenting mode jump PattermActivity Intent.setAction ("com.hdd.androidreview.PattermActivity");
ComponentName cnForAllowTaskRep = new ComponentName(
        "com.hdd.androidreview"."com.hdd.androidreview.Patterm.PattermActivity");
intent.setComponent(cnForAllowTaskRep);

break;
Copy the code

The configuration information for the PattermActivity(PActivity for short) of the application A:

<activity
    android:name=".Patterm.PattermActivity"
    android:allowTaskReparenting="true"
    android:theme="@style/AppTheme.NoActionBar" >
    <intent-filter>
        <action android:name="com.hdd.androidreview.PattermActivity"/>
    </intent-filter>
</activity>
Copy the code

Clicking the B button for T launches the PActivity for A. The allowTaskReparenting attribute of the Activity is true, so the Activity is moved to the tasks of the T app for creation. When T application press home to return to the desktop, then click A application; The PActivity will be moved back to A’s task stack.

Information in the PActivity stack that application T calls application A

T application press home to return to the desktop, and the information in the application stack of A is as follows:

AllowTaskReparenting is limited to activities started with Standard and singleTop

5. The Activity of Flags

There are two ways to specify the start mode of an Activity. One is in AndroidMenifest. XML

<activity
    android:name=".Patterm.SingleInstanceActivity"
    android:launchMode="singleInstance">
Copy the code

The other option is to specify the Intent

Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setClass(context, CycleActivity.class);
context.startActivity(intent);
Copy the code

Note: The intent specifies a higher priority than the one specified in the XML. If both modes specify the launch mode, the system uses the launch mode specified by the intent.

FLAG_ACTIVITY_NEW_TASK

This is equivalent to configuring the singleTask boot code schema in XML

FLAG_ACTIVITY_SINGLE_TOP

This is equivalent to configuring the singleTop boot code schema in XML

FLAG_ACTIVITY_CLEAR_TOP

SingTask comes with this tag. This flag clears the Activity above the target Activity in the same task stack. If the target Activity starts in standard mode, but an instance of the Activity already exists in the task stack. The system clears that instance and the Activity above it from the task, and creates a new target Activity instance and puts it at the top of the stack.

6. Matching rule of IntentFilter

There are two ways to start an Activity, one is a display call

Intent intent = new Intent(MainActivity.this, TestActivity.class);
startActivity(intent);
Copy the code

The other is to implicitly call to configure the manifest file

<! --> <activity Android :name=".Patterm.PattermActivity"
    android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
        <action android:name="com.hdd.androidreview.asdf" />
        <category android:name="com.hdd.123456"/ > <! <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

Copy the code

Activity jump code

Intent intent = new Intent(); intent.setAction("com.hdd.androidreview.asdf"); // Category must not be specified. To specify, point to // intent.addcategory (" com.hdD.123456 ") as specified in the manifest; context.startActivity(intent);Copy the code

1. action

  • You can configure more than one in the manifest file
  • The action specified by the intent matches only one of the string values in the manifest.
  • If an action is configured in the manifest, at least one must be specified and matched successfully in the intent jump.
<activity
    android:name=".Patterm.PattermActivity"
    android:theme="@style/AppTheme.NoActionBar">
    <intent-filter>
        <action android:name="com.hdd.androidreview.asdf" />
        <action android:name="com.hdd.androidreview.qwer" />
        <action android:name="12345678"/ > <! --> <category android:name="android.intent.category.DEFAULT"/> </intent-filter> </activity> intent.setAction("12345678");
context.startActivity(intent);
Copy the code

2. category

  • You can add more categories to the manifest file
  • If the intent’s addCategory() string is identical, the match succeeds.
  • Unlike an action, which must be specified in an intent, at least one match was successful. You don’t have to specify a category. If specified, at least one match is successful.
Intent intent = new Intent(); Intent.setaction (intent.setAction(intent.setAction))"com.hdd.androidreview.asdf"); // Category must not be specified. To specify, a point must be identical to the intent.addcategory (// intent.addcategory ("com.hdd.123456");
context.startActivity(intent);
Copy the code

3. data

  • The matching rules for data are similar to those for actions. If the filter defines data, then the intent must match it.

  • Data consists of mimeType and URL

MimeType indicates the media types, such as image/ JPEG, audio/ MPEG4-generic, and video/*.

URL data structure is:

<scheme>://<host>:<prot>/[<path>|<pathPrefix>|<pathPattern>]
Copy the code

Such as:

content://com.example.project:200/folder/subfolder/etc
http://www.baidu.com:80/search/info
Copy the code

Scheme:URL mode, such as HTTP, File, content, etc. If the URL does not specify scheme, the URL is invalid.

Host: indicates the URL Host name, for example, www.baidu.com. If this parameter is not specified, the URL is invalid.

Port: indicates the RUL Port number, such as 80. This parameter is valid only if scheme and host specify Port.

Path: indicates complete Path information. PathPattern: indicates the complete path information, which can contain wildcards. PathPrefix: indicates the PathPrefix

There are two things to be aware of when defining data

  1. Case one

Incomplete, and specify only mimeType or only URL.

Note: If only URL is specified, mimeType is set to content and file by default

<! <activity Android :name=".RegulationActivity">
    <intent-filter>
        <action android:name="12345678"/ > <! --> <category android:name="android.intent.category.DEFAULT" />
        <data
            android:host="www.baidu.com"
            android:scheme="http"/> </intent-filter> </activity> <! <activity Android :name=".RegulationActivity">
    <intent-filter>
        <action android:name="12345678"/ > <! --> <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="audio/mpeg" />
    </intent-filter>
</activity>

Copy the code

Java code:

// Data intent.setAction(intent.setAction)"12345678");
intent.setData(Uri.parse("http://www.baidu.com")); context.startActivity(intent); // Data intent.setAction(intent.intent.setAction ())"12345678");
intent.setType("audio/mpeg");
context.startActivity(intent);
Copy the code
  1. The second case

A complete written

Note: If the intent specifies a complete data, you must use setDataAndType() because setData() and setType() know each other’s values.

<! --> <activity Android :name=".RegulationActivity">
    <intent-filter>
        <action android:name="12345678"/ > <! --> <category android:name="android.intent.category.DEFAULT" />
        <data
            android:mimeType="audio/mpeg"
            android:host="www.baidu.com"
            android:scheme="http" />
    </intent-filter>
</activity>
Copy the code

Java code:

// Intent.setAction (intent.setAction)"12345678");
intent.setDataAndType(Uri.parse("http://www.baidu.com"), "audio/mpeg");
context.startActivity(intent);
Copy the code

Here’s another special way to write it:

<intent-filter> <data android:mimeType="audio/mpeg"
        android:host="www.baidu.com"
        android:scheme="http"<intent-filter> <data android:mimeType= /> <intent-filter"audio/mpeg" />
    <data android:scheme="http" />
    <data android:host="www.baidu.com" />
</intent-filter>

Copy the code

The two notations above have the same effect in use.

7. How do I determine whether implicit startup is successful

The first is a resolveActivity that uses an intent

ComponentName componentName = intent.resolveActivity(context.getPackageManager());
if(componentName ! = null) context.startActivity(intent);else
    Toast.makeText(context, "No match", Toast.LENGTH_SHORT).show();
Copy the code

Second, use the resolveActivity of the PackageManager

PackageManager packageManager=context.getPackageManager(); ResolveInfo resolveInfo = packageManager.resolveActivity(intent,PackageManager.MATCH_DEFAULT_ONLY); // Check whether the match is successfulif(resolveInfo ! = null) context.startActivity(intent);else
    Toast.makeText(context, "No match", Toast.LENGTH_SHORT).show();
Copy the code

The above code returns ResolveInfo not for the best Activity information, but for all activities that matched successfully. The second argument to resolveActivity() must be MATCH_DEFAULT_ONLY. See Chapter 1, Page 34, exploring the Art of Android Development for reasons that are not explained here.

The end:

It took three days to finish! In fact, this article is written to review the basic knowledge of Android, in the review process, increase the understanding of the Activity startup mode and the state in the Activity task stack. The most troublesome of the four startup modes in this article is singTask, and the most interesting is the use of the hashtag Taskffinerty. You can either write a demo or use my project test on GitHub.

reference

The end of Android development art exploration — God helps Those who help themselves

Activity startup mode and Task stack (Task) comprehensive and in-depth record (bottom)

Comprehensive and in-depth record of Activity startup mode and Task stack (Part 1)