Four startup modes for Android Activity

Posted by dai.hop on Fri, 21 Jun 2019 22:08:26 +0200

Recently, several friends have left me a message to talk about my understanding of the Activity startup mode.I think the understanding of a certain point of knowledge must be handled in order to be impressed, so I wrote a blog post today to understand the Activity startup mode with a case.Because a blog post (with a link at the end of the article) read by the District Chief before was very inspiring, this article is based on a more comprehensive explanation of that article.(
It is well known that when we launch the same activity multiple times, the system creates multiple instances and puts them on the task stack one by one according to the principle of "first in, last out". When we press the back key, an activity is removed from the top of the task stack and repeated until the task stack is empty, the system recycles the task stack.However, since then, when the system starts the same activity multiple times, it will create multiple instances repeatedly, which is obviously unreasonable. In order to optimize this problem, Android Provides four startup modes to modify the default behavior of the system.(
Enter the topic, the four start modes of Activity are as follows:
       standard,singleTop,singleTask,singleInstance 
Next, let's talk about theory and combine cases to learn all four start-up modes.(
For printing convenience, define a basic Activity that prints the log information of the current Activity in its onCreate and onNewIntent methods, mainly including the task to which it belongs, the hashcode of the current class, and the value of taskAffinity.And then we'll do it test Activity inherits this activity directly

import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

/**
 * Created by huangshuai on 2016/5/23.
 * Email: huangshuai@wooyun.org
 * Print-friendly Basic Activity
 */
public class BaseActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
        Log.i("WooYun", "*****onCreate()Method******");
        Log.i("WooYun", "onCreate: " + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
        dumpTaskAffinity();
    }

@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
        Log.i("WooYun", "*****onNewIntent()Method*****");
        Log.i("WooYun", "onNewIntent: " + getClass().getSimpleName() + " TaskId: " + getTaskId() + " hasCode:" + this.hashCode());
        dumpTaskAffinity();
    }

protected void dumpTaskAffinity(){
try {
            ActivityInfo info = this.getPackageManager()
                    .getActivityInfo(getComponentName(), PackageManager.GET_META_DATA);
            Log.i("WooYun", "taskAffinity:"+info.taskAffinity);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

standard-default mode

This mode is the default startup mode, which is the standard mode. Without specifying the startup mode, the system uses this mode to start activities by default. Each time an Activity is started, a new instance is created by rewriting it. Whoever starts the Activity of this mode in this mode belongs to the Activity that started it, regardless of the existence of the instance.In the stack.This Activity has its onCreate(), onStart(), onResume() methods all called.(
Configuration form:

<activity android:name=".standard.StandardActivity" android:launchMode="standard" > 
  • 1
  • 1

Use case:
For standard mode, android : launchMode may not be declared because the default is standard.(
The code for the Standard Activity is as follows: there is a button in the entry activity to enter the activity, and another button in the activity to start the Standard Activity.

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

/**
 * Created by huangshuai on 2016/5/23.
 * Email: huangshuai@wooyun.org
 * Standard Pattern
*/
public class ActivityStandard extends BaseActivity  {
private Buttonjump;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_standard);

jump= (Button) findViewById(R.id.btn_standard);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                Intent intent = new Intent(ActivityStandard.this, ActivityStandard.class);
                startActivity(intent);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

First we enter Standard Activity, then click on the button to enter Standard, then press the return key four times to keep returning.

The output log is as follows:

You can see that the log outputs four Standard Activities and one MainActivity, enters Standard Activity once from MainActivity, then we press the button three more times, totaling four times, and belongs to the task stack with IDs of 2087. This also verifies who started the activity of this mode, which belongs to the activity that started itThis sentence in the task stack, because the Standard Activity is started by MainActivity and the taskId of MainActivity is 208 7, so the Started Standard Activity should belong to the task with id 2087. The following three Standard Activities are started by this object with Standard Activity, so they should also be 2087, so the taskId is 2087.And the hashcode s for each activity are different, indicating that they are different instances, i.e.'Each time an activity is started, it is rewritten to create a new instance'.

singleTop-top stack multiplexing mode

In this mode, if the new activity is already at the top of the stack, then the activity will not be overridden and its onNewIntent method will be called, with the parameters of this method we can remove the information currently requested.If there is no instance of the activity at the top of the stack, the situation is the same as the standard mode.It is important to note that the onCreate(), onStart() method of this activity will not be called because it has not changed.(
Configuration form:

<activity android:name=".singletop.SingleTopActivity" android:launchMode="singleTop">
  • 1
  • 1

Use case:
ActivitySingleTop.Java

/**
 * Created by huangshuai on 2016/5/23.
 * Email: huangshuai@wooyun.org
 * SingleTop Pattern
*/
public class ActivitySingleTop extends BaseActivity {
private Button jump,jump2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_singletop);

jump = (Button) findViewById(R.id.btn_singletop);
jump2 = (Button) findViewById(R.id.btn_other);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                Intent intent = new Intent(ActivitySingleTop.this, ActivitySingleTop.class);
                startActivity(intent);
            }
        });
jump2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                Intent intent = new Intent(ActivitySingleTop.this, OtherTopActivity.class);
                startActivity(intent);
            }
        });
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

OtherTopActivity.java

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

/**
 * Created by huangshuai on 2016/5/23.
 * Email: huangshuai@wooyun.org
 */
public class OtherTopActivity extends BaseActivity {
private Button jump;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other);

jump= (Button) findViewById(R.id.btn_other);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                Intent intent = new Intent(OtherTopActivity.this, ActivitySingleTop.class);
                startActivity(intent);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

Similar to standard mode, paste output log directly

We see that, except for the first entry into the SingleTop Activity, the output is the log in the onCreate method, the onNewIntent method is called subsequently, the onCreate method is not called, and the hashcode s of the four logs are the same, indicating that there is only one instance in the stack.This is because when the first entry occurs, the instance is created without it in the stack, and when it is found on the top of the stack three times later, it is directly reused and the onNewIntent method is called.So what if there is an instance on the stack, but it's not at the top?(
First we enter SingleTopActivity from MainActivity, then jump to OtherActivity, then jump back to SingleTopActivity from OtherActivity, then jump from SingleTopActivity to SingleTopActivity to see the log of the whole process.

* We see that when entering SingleTopActivity from MainActivity, a new SingleTopActivity object is created, and the task id is the same as MainActivity. Then when jumping from SingleTopActivity to OtherActivity, a new OtherActivity is created. There are three activities in the task, MainActivity, SingleTopActivity, OtherActivity from the bottom to the top of the stackIf you jump to SingleTopActivity at this point, a new SingleTopActivity instance will be created even though there are already instances of SingleTopActivity in the stack. As can be seen from the hashCode of the log above, SingleTopActivity is at the top of the stack. If you jump to SingleTopActivity again, SingleTopActivity at the top of the stack will be reused and SingleTopActivity will be calledOnNewIntent method.This is the whole process of logging above.(
Summarize the above
The standard startup mode is the default startup mode, and each time an Activity is started, a new instance is created regardless of whether it already exists on the stack.(
The singleTop pattern is divided into three cases

  1. When an instance of this Activity already exists on the current stack and it is at the top of the stack, it will not create a new instance, but will reuse the instance at the top of the stack, and will pass in the Intent object, calling back the onNewIntent method
  2. An instance of this Activity already exists on the current stack, but when it is not at the top of the stack, it behaves like the standard startup mode and still creates a new instance
  3. When there is no instance of this Activity in the current stack, it behaves in the same standard startup mode

Both standard and singleTop startup modes create new Activity instances in the original Task stack and do not start new Tasks, even if you specify the taskAffinity property.(
So what is the taskAffinity attribute, which can be simply understood as task dependency.

  • This parameter identifies the name of a task stack required by an Activity, and by default, the name of the task stack required by all activities is the package name of the application
  • We can specify the taskAffinity property for each Activity individually to override the default value
  • The affinity of a task is determined by the taskAffinity of the root activity of the task
  • Conceptually, activities with the same affinity (that is, activities with the same taskAffinity property set) belong to the same task
  • Set an empty string for an activity's taskAffinity to indicate that the activity does not belong to any task

It is important to note that the taskAffinity property has no effect on standard and singleTop modes, even if you specify a different value for the property, and that no new task will be created in both startup modes (default value, package name, if not specified)
Specify as follows:

<activity android:name=".ActivitySingleTop" android:launchMode="singleTop" android:taskAffinity="com.castiel.demo.singletop"/>
  • 1
  • 1
<activity android:name=".ActivityStandard" android:launchMode="standard" android:taskAffinity="com.castiel.demo.standard"/>
  • 1
  • 1

singleTask-in-stack multiplexing mode

This model is complex and has a wide variety of combinations.In this mode, if an instance of this Activity exists in the stack, the Activity will be reused, regardless of whether it is on the top of the stack or not. When reused, all the Activities above it will be stacked and the onNewIntent method of the instance will be callback.There is also a matching task stack for this process, because when this mode is started, it will look for instances in the task stack it needs, which is specified by the taskAffinity property.If the task stack does not exist, it will be created.(
Configuration form:

<activity android:name=".singleTask.SingleTaskActivity" android:launchMode="singleTask" >
  • 1
  • 1

Use case:
ActivitySingleTask.java

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

/**
 * Created by huangshuai on 2016/5/23.
 * Email: huangshuai@wooyun.org
 * SingleTask Pattern
*/
public class ActivitySingleTask extends BaseActivity {
private Button jump,jump2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_task);

jump = (Button) findViewById(R.id.btn_task);
jump2 = (Button) findViewById(R.id.btn_other);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                Intent intent = new Intent(ActivitySingleTask.this, ActivitySingleTask.class);
startActivity(intent);
            }
        });
jump2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                Intent intent = new Intent(ActivitySingleTask.this, OtherTaskActivity.class);
startActivity(intent);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

OtherTaskActivity.java

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

/**
 * Created by huangshuai on 2016/5/23.
 * Email: huangshuai@wooyun.org
 */
public class OtherTaskActivity extends BaseActivity {
private Button jump;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_other_task);

jump= (Button) findViewById(R.id.btn_other);
jump.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
                Intent intent = new Intent(OtherTaskActivity.this, ActivitySingleTask.class);
                startActivity(intent);
            }
        });
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

Now, instead of specifying any taskAffinity attribute, do something similar to singleTop, that is, enter SingleTaskActivity from the entry MainActivity, jump to OtherActivity, and then jump back to SingleTaskActivity.Look at the log of the whole process.

When we enter SingleTask Activity from MainActiviyty and then OtherActivity, there are three instances of Activity on the stack and SingleTaskActivity is not at the top of the stack. When OtherActivity jumps to SingleTaskActivity, a new SingleTask Activity is not created, it is reused, and the onNewIntent method is called back.And the original OtherActivity is out of the stack, see the information below, using the command adb shell dumpsys activity activities for viewing

You can see that there are only two activities in the current stack, that is, the activities above the SingleTask Activity in the original stack are all out of the stack.(
* We see that an Activity is started using singleTask startup mode, which is still started in the original task.In fact, we did not specify the taskAffinity property, which means that, like the default value, the package name, the name of the Task created when MainActivity starts is the package name, because MainActivity also does not specify taskAffinity. When we start SingleTaskActivity, we first look for the existence of the required task stack, which is the value specified by taskAffinity.Inside is the package name. If you find it exists, you will no longer create a new task, but use it directly.The Activity instance is reused when it exists in the task, which is the in-stack reuse mode.(
At this time, if we specify a taskAffinity value for SingleTaskActivity.

<activity android:name=".ActivitySingleTask" android:launchMode="singleTask" android:taskAffinity="com.castiel.demo.singletask"/>
  • 1
  • 1

Or the previous operation.But the logs will be different.

* We see that the TaskId of the task stack to which SingleTaskActivity belongs has been transformed, that is, a new Task has been opened and then OtherActivity has been running on that Task as well.
The printed information also proves that there are two different Task s

What happens if we specify the taskAffinity property of MainActivity as well as the SingleTaskActivity property.

Yes, it's the same as they didn't specify anything.(
At this point, you have the following conclusion.
When Activity is started in singleTask startup mode, it first looks for a task stack with a corresponding name based on taskAffinity

  • If it doesn't exist, a new Task is created and a new Activity instance is created to stack into the newly created Task
  • If so, get the task stack and find out if the Activity instance exists in the task stack
    If an instance exists, stack all the Activity instances above it and then call back the onNewIntent method of the Activity instance that was started
    If the instance does not exist, create a new Activity and stack it
    In addition, we can set the activities in two different App s to be the same taskAffinity, so that although in different applications, the activities are assigned to the same Task.(
    Let's create another application, specifying that its taskAffinity is the same as before, com.xingyu.demo.singletask
<activity android:name=".MainActivity" android:launchMode="singleTask" android:taskAffinity="com.castiel.demo.singletask"/>
  • 1
  • 1

Then start an app, let him jump to the Activity, press the home key in the background, start another app and enter the Activity to see the log

* We see that SingleTaskActivity and OtherActivity that specify the same taskAffinity are started into the same task, with taskId 2169.

singleInstance - Global Unique Mode

This mode has all the features of singleTask mode except that Activity in this mode occupies a single Task stack and is globally unique, that is, it is the same instance in the whole system. Due to the characteristics of in-stack reuse, subsequent requests will not create new Activity instances unless this particular task stack is destroyed.Activity started in singleInstance mode is a singleton throughout the system. If an instance already exists when such Activiyt is started, it will be scheduled to the foreground to reuse the instance.(
Configuration form:

<activity android:name=".singleinstance.SingleInstanceActivity" android:launchMode="singleInstance" >
  • 1
  • 1

Use case:
Add an Activity as follows:
ActivitySingleInstance.java

import android.os.Bundle;

/**
 * Created by huangshuai on 2016/5/24.
 * Email: huangshuai@wooyun.org
 * SingleInstance Pattern
 */
public class ActivitySingleInstance extends BaseActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_singleinstance);
    }
}
//The configuration properties are as follows:
<activity
    android:name=".ActivitySingleInstance"
    android:launchMode="singleInstance">

    <intent-filter>
        <action android:name="com.castiel.demo.singleinstance" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

Start it in two applications using the following method

Intent intent = new Intent();
intent.setAction("com.castiel.demo.singleinstance");
startActivity(intent);
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

Do the same thing as last time, check the log

We see that when the first application starts a SingleInstanceActivity, a new Task is created because it does not exist in the system. After pressing the home key, another App is used to enter the activity. Since there is already an instance in the system, no new Task is created, the instance is reused directly, and the onNewIntent method is callback.You can see from their hashcode that this is the same instance.Therefore, we can understand that Activity initiated by SingleInstance mode has global uniqueness in the system.

Reference link: http://blog.csdn.net/sbsujjbcy/article/details/49360615

Topics: Android Java Attribute shell