Detailed explanation of the four startup modes of the activity

android:launchMode

foreword

Part of this article refers to Guo Shen's "The First Line of Code"

The launch mode of the activity is generally defined in the AndroidManifest.xml with the tag android:launchMode=" "
Next, we will introduce the differences and uses of these four launch modes.
standard singleInstance singleTop singleTask

1
Speaking of which, let's first take a look at what the return stack is?

The original text is this: Android uses tasks (Tasks) to manage activities. A task is a collection of activities stored in a stack. This stack is called the Back Stack (Back Stack).
Understanding : Now we have a bunch of activities, activity (abbreviated as a), a1, a2, a3, a4,..., an, and then store these activities in the return stack. The first a1 to be pushed into the stack is at the bottom of the stack, and the last to be pushed into the stack an is on the top of the stack, so these activities will be popped and pushed into the stack every time they work. The whole process is as follows:

1
To be honest, I still feel that the picture above is a bit abstract, so let’s take a new picture to understand it.
1

concept note

standard

Standard mode : This is the default mode of Android, when it is not declared in the AndroidManifest. First of all, Android manages activities by returning to the stack (the characteristic of the stack is first-in-last-out, just like an Arhat Tower, the data on the top of the stack is first taken out). Whenever we start a new activity, this new activity will enter the return stack and be at the top of the stack. Every time it creates a new one, it will stack an activity on the top of the stack, and it will not check whether this activity already exists in this stack.

Here we might as well regard the activity as the little star below, and the string is a return stack. Every time we start a new activity, we will string a small star. We will not care whether the one below is the same, but just keep stringing. To return after stringing, we can only return one by one, that is, take out the little stars on it one by one.
2
The schematic diagram of the standard mode is as follows (excerpted from Guo Shen's "The First Line of Code"):
2
So in the case of an appeal, when you click the button 2 times, you have to press the return key 3 times to exit the initial activity. And in this mode, every time an activity is started, a new one will be created, but it also has its application. The above is just for demonstration, usually the app will not jump from the current activity to the current activity

Application scenario: most app applications, because they generally do not jump repeatedly in the current activity.

singleTop

In this mode, for example, when starting activity A, it is found that the top of the return stack is activity A, then you can use it directly without creating a new activity instance.

Still think of activities as strings on strings, as shown in the example below
1

So like in the case of the appeal, when you click the button 2 times, you click the back button once to exit the app. But if the top element of the stack is not the activity, it will still create a new activity.
Application scenarios : most apps, or browsers or news feeds such as Toutiao.
For example, when you enter the mobile browser, I clicked on the new crown to view, and then accidentally clicked on the return home page, and then I clicked back, and it returned to the new crown page.
As shown in the picture below, I first click the search box on the main page to enter the search page, check the status of the new crown epidemic, and then click the bottom to return to the main page directly, instead of clicking the return sign that appears, I go back directly to the mobile phone, mine is on the left side of the screen finger Swipe or swipe right, and then return to the new crown page, click back again, return to the search page, return again, and enter the original main page, the whole process is as shown in the figure below. (It seems that there are advertisements on the main page that will violate the regulations, then remove those advertisement pictures and look directly at the bottom navigation bar)
1

1

singleTask

Although singleTop solves the problem of repeatedly creating a large number of top-of-stack activities, when the target activity is not at the top of the stack, a large number of repeated activities will still be created to occupy memory. The singleTask mode solves this problem very well. Every time the target activity is started, the system will search whether the activity already exists in the return stack. If it exists, all the activities above the activity in the stack will be popped out of the stack. If not Then create a new one.

s
Then you find that when there is a new activity (blue diamond), because the previous activity has been popped, a new activity will be created

Application scenarios : shopping pages, such as shopping apps such as Taobao, Pinduoduo, and JD.com.
After searching from the home page, enter the product browsing page, enter the product details page, click buy, and then jump to the payment page, after the payment is completed, the purchase is successful, and you can click the button to return to the home page directly, that is to say, product browsing Page, product details page, and payment page are popped out, and the button directly leads to the home page.

singleInstance

singleInstance will enable a new return stack (stack) to manage activities. Why do you do this?
First of all, literally, it is a single instance pattern. That is to say, Activity occupies a task stack alone, and due to the reuse characteristics in the stack, subsequent requests will not create new Activity instances, unless the task stack is destroyed (destroy()) the target activity (take
a named special) has a separate stack to store itself, so that when program A wants to call special, program B wants to call it, and program C wants to call it, the instance of this activity can be shared between programs in this mode. easily achieved. And each application has its own return stack, so the first three modes cannot solve the problem of sharing activity instances, and the singleInstance mode can play a big role.

References : According to the usual practice, first put a schematic diagram of the model quoted from "The First Line of Code".
1

diagram

There are 3 different processes (return stack), you can see that when the activity start mode is singleInstance, different programs can share the same instance.
For return stack 1: the pink arrow represents the start activity, and the blue arrow represents the return, then the order of return will be as shown in the figure below. Because activities 1.1, 1.2, 1.3 and activity excellent are not in the same stack, so return to the activity in the stack where you are first, and finally switch back to excellent
1

Application scenarios: Some system applications, such as schedule, phone, system address book, alarm clock, photo album, etc.
In QQ, WeChat or Alipay, you have to open the photo album, and all you open are the page of the photo album.

Codes demo

illustrate

Let's talk about how to write the code. File --> New -->New Project, select Empty Activity
and then, we have a mainActivity, and now create two more Activities under the com.example.xx package, named SecondActivity and ThirdActivity respectively, corresponding to Layout Put a Button inside.
You can print the log to understand the difference in different startup modes of the activity

standard code

There is no need to change the other activities here in MainActivity , or you can only create such an activity first, and demonstrate in standard mode.
android default mode

import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity {
    
    
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d(TAG, this.toString());
        Log.d(TAG, "Task id is" + getTaskId());//打印当前返回栈
        setContentView(R.layout.activity_main);
        Button but1 = findViewById(R.id.button_1);
        but1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent = new Intent(MainActivity.this,MainActivity.class);
                startActivity(intent);
            }
        });
    }
}

If you click but1 n times, you will find that you need to click the back button n+1 times to exit the app.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button1"
        android:textAllCaps="false"/>

</LinearLayout>

singleTop code

Look at it, change AndroidManifest.xml, which is the launchmode in the first picture of this article, to singleTop

Other parts of the code remain unchanged, as above standard, and then you will find that no matter how many times you click the button1 button at the beginning, you will be able to exit the program by clicking back once in the end. However, when the top element of the stack is not the activity, there will still be new activities pushed onto the stack. That is, when the top element of the stack is not it, a new one will be created when it is started again, so when jumping to multiple different pages, the effect is very similar to standard.

Now you continue to modify the code, jump from interface 1 to interface 2, then click button2, jump to interface 1, then you click back, it will return to interface 2 first, then click back to return to interface 1, and then click back Finally exit, you will find that this return is very similar to standard. Because they are all different activities, every time a new activity is started, a new activity will still be created and pushed onto the stack.

AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test4">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test4">
        <activity android:name=".ThirdActivity"
            android:exported="true"
            android:label="Third"/>
        <activity
            android:name=".SecondActivity"
            android:exported="true"
            android:label="Sec"
            android:launchMode="singleTop"/>
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="Main"
            android:launchMode="singleTop">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

MainActivity

package com.example.test4;

import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity {
    
    
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d(TAG, this.toString());
        Log.d(TAG, "Task id is" + getTaskId());//打印当前返回栈
        setContentView(R.layout.activity_main);
        Button but1 = findViewById(R.id.button_1);
        but1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });
    }
    @Override
    protected void onRestart(){
    
    
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
}

activity_main

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button1"
        android:textAllCaps="false"/>

</LinearLayout>

SecondActivity

package com.example.test4;

import androidx.appcompat.app.AppCompatActivity;

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

public class SecondActivity extends AppCompatActivity {
    
    
    private static final String TAG = "SecondActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d(TAG, this.toString());
        Log.d(TAG, "Task id is" + getTaskId());
        setContentView(R.layout.activity_second);
        Button button2 = findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent = new Intent(SecondActivity.this,FirstActivity.class);
                startActivity(intent);
            }
        });
    }
    @Override
    protected void onDestroy(){
    
    
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

activity_second.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SecondActivity">
    <Button
        android:id="@+id/button_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button2"
        android:textAllCaps="false"/>

</LinearLayout>

singleTask code

Here you will find that when you click the button to jump from page 1 to page 2, and then click the button on page 2 to jump to page 1, press the back button to exit the program.

MainActivity

package com.example.test4;

import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity {
    
    
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d(TAG, this.toString());
        Log.d(TAG, "Task id is" + getTaskId());//打印当前返回栈
        setContentView(R.layout.activity_main);
        Button but1 = findViewById(R.id.button_1);
        but1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });
    }
    @Override
    protected void onRestart(){
    
    
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
}

xml does not change
SecondActivity

package com.example.test4;

import androidx.appcompat.app.AppCompatActivity;

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

public class SecondActivity extends AppCompatActivity {
    
    
    private static final String TAG = "SecondActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d(TAG, this.toString());
        Log.d(TAG, "Task id is" + getTaskId());
        setContentView(R.layout.activity_second);
        Button button2 = findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent = new Intent(SecondActivity.this,MainActivity.class);
                startActivity(intent);
            }
        });
    }
    @Override
    protected void onDestroy(){
    
    
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

second.xml does not change
AndroidManifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test4">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test4">
        <activity android:name=".ThirdActivity"
            android:exported="true"
            android:label="Third"/>
        <activity
            android:name=".SecondActivity"
            android:exported="true"
            android:label="Sec"
            android:launchMode="singleTask"/>
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="Main"
            android:launchMode="singleTask">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

singleInstance code

Here, because the secondActivity mode is set to singleInstance, MainActivity and ThirdActivity are in a return stack, and number 2 is in a single stack. So you will find that when you click button 1 to reach page 2, then click button 2 to reach page 3, when you click the back button, you will return to page 1, then click the back button to return to page 2, and then click back to exit the app.

MainActivity.java

import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity {
    
    
    private static final String TAG = "MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d(TAG, this.toString());
        Log.d(TAG, "Task id is" + getTaskId());//打印当前返回栈
        setContentView(R.layout.activity_main);
        Button but1 = findViewById(R.id.button_1);
        but1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                startActivity(intent);
            }
        });
    }
    @Override
    protected void onRestart(){
    
    
        super.onRestart();
        Log.d(TAG, "onRestart");
    }
}

SecondActivity.java

import androidx.appcompat.app.AppCompatActivity;

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

public class SecondActivity extends AppCompatActivity {
    
    
    private static final String TAG = "SecondActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d(TAG, this.toString());
        Log.d(TAG, "Task id is" + getTaskId());
        setContentView(R.layout.activity_second);
        Button button2 = findViewById(R.id.button_2);
        button2.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent = new Intent(SecondActivity.this,ThirdActivity.class);
                startActivity(intent);
            }
        });
    }
    @Override
    protected void onDestroy(){
    
    
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

ThirdActivity.java

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.util.Log;

public class ThirdActivity extends AppCompatActivity {
    
    
    private static final String TAG = "ThirdActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d(TAG, "Task id is" + getTaskId());
        setContentView(R.layout.activity_third);
    }
}

androidmanifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.test4">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Test4">
        <activity android:name=".ThirdActivity"
            android:exported="true"
            android:label="Third"/>
        <activity
            android:name=".SecondActivity"
            android:exported="true"
            android:label="Sec"
            android:launchMode="singleInstance"/>
        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="Main">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button_1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button1"
        android:textAllCaps="false"/>

</LinearLayout>

activity_second.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SecondActivity">
    <Button
        android:id="@+id/button_2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Button2"
        android:textAllCaps="false"/>
        
</LinearLayout>

activity_third.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".ThirdActivity">

    <TextView
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:layout_marginStart="52dp"
        android:layout_marginLeft="52dp"
        android:layout_marginTop="340dp"
        android:text="Hello,smart person !!!"
        android:textSize="36sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

Guess you like

Origin blog.csdn.net/qq_43738932/article/details/126022497