"The First Line of Code" Chapter 2: Exploring the Activity Activity

First, the basic usage of the activity

To understand simply, an activity is a page that you can see, usually one activity per page.

1. Manually create a project

Create a new project and select add NoActivity. For the project generated at this time, there is no activity in the package under java. So you need to create a new activity.
Right-click the com.example.activitytest package-New-Activity-Empty Activity, and a dialog box for creating an activity will pop up. We name the activity FirstActivity, and do not check the two options Generate Layout File and Launcher Activity.
Checking Generate Layout File means that a corresponding layout file will be automatically created for FirstActivity. Checking LauncherActivity means that FirstActivity will be automatically set as the main activity of the current project. Since you are creating an activity manually for the first time, these automatically generated things are temporary Don't check them all, we will manually complete them one by one below.
insert image description here

public class FirstActivity extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
    }
}

Any activity in the project should override the Activity's onCreate() method, and the newly created one has been written for us by default.

2. Create and load the layout

As we said before, the design of Android programs pays attention to the separation of logic and view. It is best that each activity can correspond to a layout. The layout is used to display the interface content, so we will manually create a layout file now.
Right-click the app/src/main/res directory-New-Directory, and a window for creating a new directory will pop up. Here, create a directory named layout first. Then right-click on the layout directory and click Layoutresource file, and a window for creating a new layout resource file will pop up. We name this layout file first laout, and the root element is the default.
Then write the button code:

<Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="测试按钮"/>
android:id 是给当前的元素定义一个唯一标识符,之后可以在代码中对这个元素进行操作。你可能会对@+id/button 1这种语法感到陌生,但如果把加号去掉,变成@id/button 1,这样你就会觉得有些熟悉了吧,这不就是在 XML中引用资源的语法吗?只不过是把 string 替换成了id。是的,如果你需要在XML中引用一个id,就使用@id/id name 这种语法,而如果你需要在XML中定义一个id,则要使用@+id/id name 这种语法。

随后android:layout width 指定了当前元素的宽度,这里使用match parent 表示让当前元素和父元素一样宽。android:layout height 指定了当前元素的高度,这里使用 wrap content 表示当前元素的高度只要能刚好包含里面的内容就行。android:text 指定了元素中显示的文字内容

In this way, the layout file is written, and then the layout needs to be loaded in the activity .

protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
+        setContentView(R.layout.first_layout);
}

Then register this activity in the AndroidManifest file:

    <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.MyApplicationTest">
        <activity
            android:name=".FirstActivity"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

You can see that the activity has been registered. But two lines of code inside the intent-filter tag are missing. As I said before, these two lines of code indicate that FirstActivity is the main activity of this project. Click the application icon on the mobile phone, and this activity will be launched first.
Run the project after writing in this way, and you can see the effect:
insert image description here
so the process is as follows:

1,创建新的活动
2,创建新的layout布局
3,在活动中引入创建的layout
4,在manifext文件中注册活动。

3. Use toast in the activity

A button has been written above. At this time, you can get the button and bind an event to it.

setContentView(R.layout.first_layout);
Button button1=(Button) findViewById(R.id.button);
button1.setOnClickListener(new View.OnClickListener() {
    
    
    @Override
    public void onClick(View view) {
    
    
        Toast.makeText(FirstActivity.this, "测试toast", Toast.LENGTH_SHORT).show();
    }
});

You can see that what findViewById returns here is the view object, which is transformed into a button object, and then calls the setOnClickListener method to register a listener for the button. The onClick method in the listener is executed when the button is clicked.
And here we need to customize the content of the onClick method.
The usage of Toast is very simple. Create a Toat object through the static method makeText(), and then call show() to display the Toast. It should be noted here that the makeText() method needs to pass in 3 parameters.

第一个参数是 Context,也就是 Toast要求的上下文,由于活动本身就是一个 Context 对象,因此这里直接传人 FirstActivity.this 即可。
第二个参数是 Toast 显示的文本内容。
第三个参数是 Toast显示的时长,有两个内置常量可以选择 Toast.LENGTH SHORT和 Tast.LENGTH LONG

4. Use the menu in the activity

First create a menu folder under the res directory, click res directory-New-Directory, enter the folder name menu, and click OK. Then create a new menu file named main under this folder, right-click the menu folder-New-Menu resource file, and add the following code:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/add_item"
        android:title="Add" />
    <item
        android:id="@+id/remove_item"
        android:title="Remove" />
</menu>

That is to say, there are all resource files in res. The layout content of the menu is written here, and it needs to be mounted in the corresponding activity to display it. Then return to FirstActivity to rewrite the onCreateOptionsMenu() method. The rewriting method can be Use the Ctrl+O shortcut (control + O on Mac).

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
    
    
        getMenuInflater().inflate(R.menu.main,menu);
        return true;
    }

You can get the MenuInflater object through the getMenuInflater() method, and then call its inflate() method to create a menu for the current activity.

inflate()方法接收两个参数,第一个参数用于指定我们通过哪一个资源文件来创建菜单,这里当然传入 r.menu.main。第二个参数用于指定我们的菜单项将添加到哪一个Menu对象当中,这里直接使用onCreateOptionsMenu()方法中传人的 menu参数然后给这个方法返回 true,表示允许创建的菜单显示出来,如果返回了 false,创建的菜单将无法显示。

Of course, it is not enough to just display the menu. We define the menu not only for viewing, but the key is to make the menu really usable, so we need to define the menu response event again. Rewrite the on0optionsItemSelected() method in FirstActivity.

@Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
    
    
        switch (item.getItemId()){
    
    
            case R.id.add_item:
                Toast.makeText(this, "增加按钮被点击", Toast.LENGTH_SHORT).show();
                break;
            case R.id.remove_item:
                Toast.makeText(this, "移除按钮被点击", Toast.LENGTH_SHORT).show();
                break;
            default:
        }
        return true;
    }

In the on0optionsItemSelected() method, call item.getItemId() to determine which menu item we clicked, and then add our own logic processing to each menu item. As mentioned above, android:id="@+id/add_item" will add an id to add_item, so here R.id.add_item can get its id. So the menu is created.

5. Destroy an activity

On the interface, we can destroy the current activity by pressing the back key. However, if you want to implement it in code, you can use a finish() method provided by the Activity class. We can destroy the current activity by calling this method in the activity.

button1.setOnClickListener(new View.OnClickListener() {
    
    
      @Override
      public void onClick(View view) {
    
    
          finish();
      }
  });

In this way, clicking the button will destroy the current activity.

Two, use Intent to shuttle between activities

An activity was created above, but it is impossible for a project to have only one activity, so how to jump between multiple activities? This requires the use of Intent to complete.

1. Build the second activity

Right-click the activity, create a new enpty activity, and check Generate Layout File, name the layout file second_layout, but do not check the Launcher Activity option.
Click Finish to complete the creation of Android Studio, which will automatically generate the SecondActivity, java and second layoutxml files for us. However, the automatically generated layout code may be a bit complicated for you at present, here we still use the most familiar LinearLayout, edit second layout.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=".SecondActivity">

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="第二个按钮" />
</androidx.constraintlayout.widget.ConstraintLayout>

Then look at secondActivity, the editor has written a reference to this layout for us:

 @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.second_layout);
    }

Next, register this activity in the manifest file, and you can see that it has been automatically registered. It is worth noting that because it is not the main activity, the intent-filter tag is not required.

<activity
    android:name=".FirstActivity"
    android:exported="true" >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>
<activity
    android:name=".SecondActivity"
    android:exported="true" />

The second activity has been created here, and the next question is how to start this activity. Need to use Intent.

2. Use explicit Intent to complete the switching of activities

Intent is an important way to communicate between components in an Android program. It can not only indicate the action that the current component wants to perform, but also transfer data between different components. Intent can generally be used in scenarios such as starting activities , starting services , and sending broadcasts . Here we only talk about the start-up activities.
Intent can be roughly divided into two types: explicit intent and implicit intent. Let's first look at how to use explicit intent.

Intent有多个构造函数的重载,其中一个是Intent(Context packageContext,Class<?>cls)。这个构造函数接收两个参数。
第一个参数 Context 要求提供一个启动活动的上下文。
第二个参数 class 则是指定想要启动的目标活动,通过这个构造函数就可以构建出 Intent 的“意图”。
 Activity类中提供了一个startActivity()方法,这个方法是专门用于启动活动的,它接收一个 Intent 参数,这里我们将构建好的 Intent 传入startActivity()方法就可以启动目标活动了。

The specific code is as follows:

 Button button1=(Button) findViewById(R.id.button);
        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
                //这里这两个参数,指定从当前活动跳转目标活动。
                startActivity(intent);
            }
        });

In this way, after clicking the button, you can switch to the second page. It is worth noting that the first page activity has not been destroyed. It can be understood that the new activity is overlaid on the old activity. Because I destroy the current activity on the second page, I will go to the first activity.

3. Use the usage of implicit Intent

Compared with the explicit Intent, the implicit Intent is much more implicit. It does not clearly indicate which activity we want to start, but specifies a series of more abstract information such as action and category, and then it is handed over to the system to analyze the Intent. And help us find the right activities to launch.
By configuring the content of <intent-filter under the tag, you can specify the action and category that the current activity can respond to, open AndroidManifest.xml, and add the following code:

 <activity
            android:name=".SecondActivity"
            android:exported="true" >
            <intent-filter>
                <action android:name="com.example.myapplicationtest.ACTION_START" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>

In the label, we indicate that the current activity can respond to the com.example.activitytest.ACTIONSTART action, and the label contains some additional information, which more precisely indicates the category that may be included in the Intent that the current activity can respond to. Only when the content in and can match the action and category specified in the Intent at the same time, this activity can respond to the Intent.
Modify the click event of the button in FirstActivity, the code is as follows:

        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent("com.example.myapplicationtest.ACTION_START");
                startActivity(intent);
            }
        });

It can be seen that we used another constructor of Intent and passed in the action string directly, indicating that we want to start an activity that can respond to the com.example.activitytest.ACTION START action. Didn’t it say that it needs to be matched with the same time to respond? Why don’t you see where there is a specified category? This is because android.intent, category.DEFAULT is a default category, and it will be called when the startActivity() method is called. Automatically add this category to the Intent. Then you can find the corresponding activity and start it.
Only one action can be specified in each Intent, but multiple categories can be specified. At present, there is only one default category in our Intent, so let's add another one now.
Modify the click event of the button in FirstActivity, the code is as follows:

        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent("com.example.myapplicationtest.ACTION_START");
                intent.addCategory("com.example.myapplicationtest.MY_CATEGORY");
                startActivity(intent);
            }
        });

After adding here, the corresponding category cannot be found after clicking the button. In order to make it respond to the corresponding activity, it is necessary to add a category declaration in menifext:

            <intent-filter>
                <action android:name="com.example.myapplicationtest.ACTION_START" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="com.example.myapplicationtest.MY_CATEGORY"/>
            </intent-filter>

4. Use implicit Intent to start the activities of other programs

Using implicit Intent, we can not only start activities in our own program, but also start activities of other programs, which makes it possible to share functions between multiple Android applications. For example, if you need to display a web page in your application, you don't need to implement a browser yourself (in fact, it is not possible, but you only need to call the system browser to open this web page. Modify the button in
FirstActivity Code for click event:

        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(Intent.ACTION_VIEW);
                intent.setData(Uri.parse("http://www.baidu.com"));
                startActivity(intent);
            }
        });

Then modify this line of code in menifest and add an ignore (if you don't change it, you will get an error):

            <intent-filter  tools:ignore = "AppLinkUrlError">
                <action  android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="http"/>
            </intent-filter>

In this way, when you click the button, a pop-up window will appear, allowing you to choose an activity, whether to open activity 3 or open the default browser.
Here is because of the button event, matching multiple activities. So a pop-up window is needed for the user to choose.
Achieved effect:
insert image description here
Next, let’s take a look at opening the phone book of the system:

  button1.setOnClickListener(new View.OnClickListener() {
    
    
      @Override
      public void onClick(View view) {
    
    
          Intent intent=new Intent(Intent.ACTION_DIAL);
          intent.setData(Uri.parse("100861"));
          startActivity(intent);
      }
  });

5. Pass data to the next activity

In the words of the front end, it is how to pass parameters when routing jumps.

传递参数:intent.putExtra("extra_data",data);
接收参数: 	Intentintent=getIntent();
			String data=intent.getStringExtra("extra_data");
 			Log.d("EecondActivity",data);

Pass the data in the first activity:

        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                String data="这是要传递的数据";
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
                intent.putExtra("extra_data",data);
                startActivity(intent);
            }
        });

Receive parameters in the second activity:

 Intentintent=getIntent();
 String data=intent.getStringExtra("extra_data");
 Log.d("EecondActivity",data);

6. Return data to the previous activity

Whether it is the back key or the code finish() to destroy the current activity, we can pass data to the previous activity when the activity is destroyed. This requires the use of the startActivityForResult() method in the Activity, which is also used to start the activity, but this method expects to return a result to the previous activity when the activity is destroyed.

startActivityForResult()方法接收两个参数,
第一个参数还是 Intent,
第二个参数是请求码,用于在之后的回调中判断数据的来源。

In the click event of the first activity write:

       button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                String data="这是要传递的数据";
                Intent intent=new Intent(FirstActivity.this,SecondActivity.class);
                startActivityForResult(intent,1);//请求码传入唯一值用来明确是它启动的活动即可,这里用1
            }
        });

Then register the click event for the button in the second activity, and add the logic of returning data to the click event:

 public void onClick(View view) {
    
    
    Intent intent=getIntent();
    intent.putExtra("data_return","返回给上一个活动的信息");
    setResult(RESULT_OK,intent);//这个方法专门用于向上一个活动返回数据
    //第一个参数:用于返回处理结果,RESULT_OK是内置常量-1
    //第二个参数:带有参数的Intent
    finish();
}

Since we use the startActivityForResult() method to start SecondActivity, the onActivityResult() method of the previous activity will be called back after SecondActivity is destroyed, so we need to rewrite this method in FirstActivity to get the returned data, as shown below:

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    
    
        super.onActivityResult(requestCode, resultCode, data);
        switch (requestCode){
    
    
            //。由于在一个活动中有可能调用startActivityForResult()方法去启动很多不同的活动
            // 每一个活动返回的数据都会回调到onActivityResult()这个方法中,
            // 因此我们首先要做的就是通过检查 requestCode 的值来判断数据来源。
            // 确定数据是从SecondActivity返回的之后,我们再通过 resultCode 的值来判断处理结果是否成功。
            case 1:
                if(resultCode==RESULT_OK){
    
    
                    String returnedData=data.getStringExtra("data_return");
                    Log.d("FirstActivity",returnedData);
                }
                break;
            default:
        }
    }

After this, because startActivityForResult is used to open Activity 2 in Activity 1, enter Activity 2, click the button to destroy the activity, and it can be monitored by the onActivityResult method of Activity 1, execute the internal code, and identify which activity returned the trigger according to the requestCode , and then execute the corresponding code.
But if Back destroys the second activity, obviously the callback will not be executed, so how to solve it?
We can solve this by overriding the onBackPressed() method in the second activity.

    @Override
    public void onBackPressed() {
    
    
        Intent intent=getIntent();
        intent.putExtra("data_return","返回给上一个活动的信息");
        setResult(RESULT_OK,intent);//这个方法专门用于向上一个活动返回数据
        //第一个参数:用于返回处理结果,RESULT_OK是内置常量-1
        //第二个参数:带有参数的Intent
        finish();
    }

Three, the life cycle of the activity

1. The concept of return stack

insert image description here
That is to say, each activity is a layer in the stack, and the user looks from top to bottom, just like the layer concept of ps.

2. Active state

There are 4 states in the life cycle of each activity.
Operating status:

就是处在栈顶的活动

suspended state

不处于栈顶,但是用户仍然可见的活动(顶层活动不覆盖全页,就会让底下的人活动可见了)

stop state

当一个活动不处于顶层,并且不可见的时候。这时候系统仍然保留相应的状态和成员变量,但可能被回收。

destroyed state

当活动从栈中移除的时候就变成了销毁状态。

3. Activity life cycle

onCreate()。它会在活动第一次被创建的时候调用。你应该在这个方法中完成活动的初始化操作,比如说加载布局、绑定事件等。【完整】
口 onstart()。这个方法在活动由不可见变为可见的时候调用。【可见】
口 onResume()。这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。【前台】
口 onPause()。这个方法在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在这个方法中将一些消耗 CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶活动的使用。【前台】
口onstop()。这个方法在活动完全不可见的时候调用。它和 onPause()方法的主要区别在于,如果启动的新活动是一个对话框式的活动,那么 onPause()方法会得到执行,而onstop()方法并不会执行。【可见】
口 onDestroy()。这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。【完整】
口 onRestart()。这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。

4. The life cycle of experience activities

insert image description here
Create several new activities, the layout of the main activity:

<?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:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动活动页1"/>

    <Button
        android:id="@+id/button2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="启动弹窗页2"/>

</LinearLayout>

Main activity:

package com.example.activitylifecycletest;

import androidx.annotation.LongDef;
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 {
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d("TAG", "onCreate: ");
        Button startNormalActivity=(Button) findViewById(R.id.button);
        Button startDialogActivity=(Button) findViewById(R.id.button2);
        startNormalActivity.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(MainActivity.this,NormalActivity.class);
                startActivity(intent);
            }
        });
        startDialogActivity.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(MainActivity.this,DialogActivity.class);
                startActivity(intent);
            }
        });
    }

    @Override
    protected void onStart() {
    
    
        super.onStart();
        Log.d("TAG", "onStart: ");
    }

    @Override
    protected void onResume() {
    
    
        super.onResume();
        Log.d("TAG", "onResume: ");
    }

    @Override
    protected void onPause() {
    
    
        super.onPause();
        Log.d("TAG", "onPause: ");
    }

    @Override
    protected void onStop() {
    
    
        super.onStop();
        Log.d("TAG", "onStop: ");
    }

    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        Log.d("TAG", "onDestroy: ");
    }

    @Override
    protected void onRestart() {
    
    
        super.onRestart();
        Log.d("TAG", "onRestart: ");
    }
}

5. Temporarily store activity data before activity recycling

As mentioned above, the activity enters the stop state when it is invisible, and at this time the activity may be recycled. If it is a page such as a form, the user clicks to return, and the information just entered will be lost. In order to avoid this situation.
We want to be able to listen for the activity to be recycled. Once the activity is recycled, our function is triggered. Store the data temporarily. When returning to this activity, reassign the value.
The Activity object provides this api to store numbers:

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
    
    
        //当前活动被销毁前会执行这里的代码
        super.onSaveInstanceState(outState);
        String testData="这是存储的一些信息";
        //存储对应数据类型的数据
        outState.putString("data_key",testData);
    }

How to get the number? Note that the activity's onCreate() method will pass in a Bundle as a parameter, that is, get the number through it:

 if(savedInstanceState!=null){
    
    
     String testData=savedInstanceState.getString("data_key");
     Log.d("取出来的数的值", testData);
 }

6. Activity start mode

There are four ways to start an activity: standard, singleTop, singleTask, singleInstance. The launch mode can be selected by specifying the android:launchMode attribute to the tag in AndroidManifest.xml.
[standard]
Standard is the default activity startup method. When an activity is started, an activity is pushed to the top of the task stack. The activities we created above all use this startup method.
Open a new project, write a button, and write the following code in the activity:

    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d("新创建", "onCreate: ");
        setContentView(R.layout.first_layout);
        Button button1=(Button) findViewById(R.id.button);
        button1.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                Intent intent=new Intent(FirstActivity.this,FirstActivity.class);
                startActivity(intent);
            }
        });
    }

At this time, if you click the button twice, two more current activities FirstActivity will be created, and you need to press Return three times to exit the program.
[singleTop]
When using the singleTop mode, if you find that the top of the return stack is already the activity when you start the activity, you can use it directly without creating a new activity instance.
Modify the menifext file:

 <activity
     android:name=".FirstActivity"
     android:launchMode="singleTop"
     android:exported="true">
     <intent-filter>
         <action android:name="android.intent.action.MAIN" />
         <category android:name="android.intent.category.LAUNCHER" />
     </intent-filter>
 </activity>

Clicking the button again at this time will not create a new activity. But if you create a non-stack activity, it will still be created as usual.
[singleTask]
singleTop only solves the problem of repeated creation of activities at the top of the stack, but it cannot solve the problem of repeated creation of A activities like ABABACA. So there is singleTask again. It guarantees that the activity is unique, and if it already exists, it will not be created, but will be reused directly. Move it from the stack directly to the top of the stack.
[singleInstance]
The above three have achieved that there is only one instance of an activity in each activity stack. Why is there still singleInstance?
This is because there may be multiple apps, assuming it is like abc, there will be multiple call stacks ABC.
Now there is an activity H, which will be called by all three programs abc. Isn't that going to enter three activity stacks, that is, three instances are created.
To solve this problem, you can use singleInstance, its principle is to create a new activity stack. Put the current activity into this new activity stack, and let other programs share this activity stack.
insert image description here
At this time, we can create three new activities, ABC, set AC to android:launchMode="singleTop", and set B to singleInstance, then A jumps to B and then jumps to C, as follows:

    <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.MyApplicationTest">
        <activity
            android:name=".ThirdActivity"
            android:launchMode="singleTop"
            android:exported="true" >
        </activity>
        <activity
            android:name=".FirstActivity"
            android:launchMode="singleTop"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SecondActivity"
            android:launchMode="singleInstance"
            android:exported="true">
        </activity>
    </application>

Then write the first activity on the page, jump to the second activity, and then jump to the third activity. The resulting activity stack will be two, as shown below:
insert image description here
that is:
the singleInstance is set in the activity, and the activity is placed separately in the shared activity stack after it is created. Others that set singleTop enter their own activity stack normally.
In actual use, if there are multiple programs, there are multiple active stacks, and then share a shared stack.
The return of the activity stack is that the next activity stack will not be reached until the stack returns to empty.
That is: if you press Enter at this time, it will first go from thirdActivity to firstActivity, and then to SecondActivity in the shared stack.

7. Best Practices for Events

[Know which activity you are currently in]
Create a new ordinary Java class, right-click com.example.myApplicationTest-new-Java class, and then write a new class, let it inherit AppCompatActivity, rewrite Oncreate, and print the current activity name:

public class BaseActivity extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d("当前活动", getClass().getSimpleName());
    }
}

Then let activities 123 inherit this class. So the effect achieved is that when each activity is just opened, it will print out the name of the current activity. The main thing here is super.onCreate(savedInstanceState); the onCreate of the parent class will be executed, so it can be printed out.
[Exit the program anytime, anywhere]
As shown in the singleInstance above, when we are in thirdActivity, we need to press the return key three times to exit the program. Now we want to close the program directly?
We only need to create a new array to manage all the activities. When we want to exit the program directly, traverse this array and destroy all the activities in the form of finish(). Then kill the current process.
Create a new ActivityCollector class:

public class ActivityCollector {
    
    
    //新建一个类型为List,内容为Activity类型的数组activities
    public static List<Activity> activities =new ArrayList<Activity>();
    //定义方法,往activities数组中添加值
    public static void addActivity(Activity activity){
    
    
        activities.add(activity);
    }
    //定义方法,从activities中移除值
    public static  void removeActivity(Activity activity){
    
    
        activities.remove(activity);
    }
    //移除所有活动
    public static void finishAll(){
    
    
        for (Activity activity : activities) {
    
    
            if(!activity.isFinishing()){
    
    
                activity.finish();
            }
        }
    }
}

Then modify the code in BaseActivity in the previous point, and add this activity to the array at the beginning of each activity. On each activity destruction, remove the class from the array:

public class BaseActivity extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        Log.d("当前活动", getClass().getSimpleName());
        ActivityCollector.addActivity(this);
    }

    @Override
    protected void onDestroy() {
    
    
        super.onDestroy();
        ActivityCollector.removeActivity(this);
    }
}

In this way, when we want to close the program directly, we can directly call ActivityCollector.finishAll() to destroy all activities:

public class ThirdActivity extends BaseActivity {
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.third_layout);
        Button button3=(Button) findViewById(R.id.button3);
        button3.setOnClickListener(new View.OnClickListener() {
    
    
            @Override
            public void onClick(View view) {
    
    
                ActivityCollector.finishAll();
            }
        });
    }
}

[The best way to write an activity]
As mentioned above, data can be passed between activities. If you want to pass multiple parameters, write it like this according to the previous method:

 public void onClick(View view) {
    
    
     Intent intent=new Intent(SecondActivity.this,ThirdActivity.class);
     intent.putExtra("param1","data1");
     intent.putExtra("param2","data2");
     startActivity(intent);
 }

But it would be more reasonable and easier to maintain like this:

    //在SecondActivity中定义一个方法,启动活动传参专用
    public static void actionStart(Context context, String data1, String data2){
    
    
        Intent intent=new Intent(context,ThirdActivity.class);
        intent.putExtra("param1","data1");
        intent.putExtra("param2","data2");
        context.startActivity(intent);
    }

Then do it directly in one line in onCreate:

 public void onClick(View view) {
    
    
       //直接调用这个方法
       SecondActivity.actionStart(SecondActivity.this,"data1","data2");
   }

Guess you like

Origin blog.csdn.net/weixin_42349568/article/details/128806721