当前位置: 首页 > news >正文

7天入门Android开发之第2天——四大组件之活动

一、活动是什么

        活动(Activity)是 Android 应用程序中的一个重要组件,它代表用户界面上的单个窗口,通常会填充整个屏幕。通过活动,可以创建各种各样的用户界面,并控制界面的行为。活动可以包含各种 UI 元素,例如按钮、文本框、图像等,以及与用户交互的逻辑,比如响应用户的点击、触摸等操作。通过定义不同的活动,可以实现应用程序中的各种功能和界面。

二、创建一个活动

        在上一节我们只是创建了一个HelloWorld项目,在界面上显示Hello world字符串。其实在着项目中android studio已经为我们创建了一个活动,就是通过这个活动来显示Hello world字符串。现在原来的HelloWorld项目中来重新创建一个活动。

        1)鼠标右键点击com.example.helloworld在出现的侧边栏选择New再点击Activity,最后出现的侧边栏就是活动的样式,可以选择自己相适应的活动减少开发时间,选择Empty Views Activity就好

  

图2-1 创建活动

        2)出现这个界面,其中Activity为活动名,,勾选Generate a Layout File,表示创建layout作为活动界面,Layout Name 表示创建layout文件的文件名,Launcher Activity表示是否将该活动作为主活动,也就是作为第一个显示的界面,暂时不要勾选;package name 表示该活动存放在那个包下面;Source Language表示使用那种开发语言,Java即可;点击finish,完成活动的创建。

图2-2 设置活动属性

        3)活动创建后可以再com.example。helloworld下面看到FirstActivist,现在点击运行会发现界面仍然是之前的Hello world字符串,如图2我们的FirstActivity是没有添加任何控件的,应该是空白的,仍然显示的是之前Android studio创建的活动,那怎么才能显示刚才创建的活动呢。首先先说第一种办法,在Androidmanifests.xml中修改。将Android studio自动注册的部分,如下

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

图2-3 原始Androidmanifests.xml

修改为如下,可以看到只是将

         <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

修改了位置,以及android:exported设置为true,,这些语句就是将程序入口点设置为当前活动,有且只能有一个不然程序找不到入口点,Android 12 中,如果一个活动(Activity)可启动,则必须将其导出(exported),这样它才能被其他应用程序调用,android:exported必须设置为true。

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

图2-4 修改后Androidmanifests.xml

现在我们来点击运行可看到如图2-7

            

           图 2-6 原始显示活动                                    图2-7 修改后显示FirstActivity活动

三、给活动添加控件

        刚才我们创建活动的时Generate a Layout File,创建完活动即可在res/layout下面看到我们创建的xml文件,如图2-8,通过这个文件可以为这个界面添加各种各样的控件,

图2-8

1)常用布局

        打开activity_first.xml文件,点击右上角split就看看见创建控件后的界面的样式了,如图2-9

图 2-9

在中间编辑区可以看到Android studio自动生成的布局为

<?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=".FirstActivity"></androidx.constraintlayout.widget.Con

我们来详细解释每一行

<?xml version="1.0" encoding="utf-8"?>表示这个是xml文件使用utf-8编码;

<androidx.constraintlayout.widget.ConstraintLayout 表示使用ConstraintLayout布局

xmlns:android="http://schemas.android.com/apk/res/android声明了 Android 的命名空间,使得在文件中可以使用 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指定了 ConstraintLayout 的宽度和高度分别与父容器的宽度和高度相匹配,填满整个屏幕。

tools:context=".FirstActivity"指定了与这个布局文件相关联的 Activity 类的名称,这在布局预览中很有用。

我们暂时不用ConstraintLayout布局,使用LinearLayout布局,LinearLayout 是一个在垂直或水平方向排列子视图的布局容器。将之前的代码情况,重新修改如下

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

可以看到添加了一个orientation字段用来表示布局时垂直还是水平,使用垂直布局。

2)添加控件

        之前的布局是空白的,现在往布局里面添加一个按钮控件。

        android:layout_width="match_parent"  //宽度填充到界面最大
        android:layout_height="wrap_content" //高度适应文字大小
        android:id="@+id/btn"                           //控件id,不可重复
        android:text="Button"/>                        //按钮名

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".FirstActivity"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn"android:text="Button"/></LinearLayout>

        现在再添加一个按钮与上一个按钮水平,现在android:layout_width="wrap_content"和android:layout_height="wrap_content"都调到适应文字大小,并且两个按钮都被限制在LinearLayout中使用 android:orientation="horizontal"水平布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".FirstActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/btn"android:text="Button"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:id="@+id/btn2"android:text="Button"/></LinearLayout>
</LinearLayout>

可以看到两个按钮在同一水平线上了,但是感觉怪怪的,我们现在让这两个按钮一个按钮占一行的1/2.

android:layout_width="0dp"                                        //默认值
android:layout_height="wrap_content"                        //高度适应文字大小
android:layout_weight="1"                         //如果一个 LinearLayout 中的多个子视图都设置了 layout_weight 属性,它们会根据各自的权重值来分配剩余空间。权重值越大,分配到的空间就越多。也就是说layout_weight总和假如为2,这个值就表示1/2,占一半的空间。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".FirstActivity"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/btn"android:text="Button"/><Buttonandroid:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="1"android:id="@+id/btn2"android:text="Button"/></LinearLayout>
</LinearLayout>

 3)在代码使用按钮控件

        现在已经创建好了控件,如何在代码中使用它呢?回到FirstActivity.Java文件中添加如下代码

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;public class FirstActivity extends AppCompatActivity {private Button btn ,btn2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_first);btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});btn2 = findViewById(R.id.btn2);btn2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});}
}

        在活动中,可以通过 finaViewById()方法获取到在布局文件中定义的元素,这里我们传人R.id.btn,来得到按钮的实例,这个值是刚才在 first_layout.xml 中通过 android:id 属性指定的。findViewById()方法返回的是一个View对象,我们需要向下转型将它转成 Button 对象。得到按钮的实例之后,我们通过调用set0nclickListener()方法为按钮注册一个监听器点击按钮时就会执行监听器中的 onClick()方法。现在我们就可以点击按钮实现某种功能了。

4)Toast在活动中的使用

        Toast是一个在Android中非常方便的一种提醒方式,它可以在屏幕上短暂显示提示信息。

        使用Toast也非常简单,只要使用其中的静态方法makeText获取到Toast的实例,再通过show方法将提示信息显示出来。

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class FirstActivity extends AppCompatActivity {private Button btn ,btn2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_first);btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(FirstActivity.this,"这是第一个按钮",Toast.LENGTH_SHORT).show();}});btn2 = findViewById(R.id.btn2);btn2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Toast.makeText(FirstActivity.this,"这是第二个按钮",Toast.LENGTH_SHORT).show();}});}
}

    

 四、使用Intent跳转活动

        从之前学的知识知道只有在<intent-filter>标签内设置为主活动才可以显示界面,那么怎么才能从当前活动跳转到另外一个活动呢?在Android可以使用intent跳转活动。Intent 大致可以分为两种:显式Intent和隐式Intent,我们主要学习一下显式Intent 如何使用。

1)创建SecondActivity

        右键com.example.helloworld新建Activity,不创建layout文件,点击finish完成创建。

2)创建layout文件

         右键layout文件夹,点击XML 新建Layout XML文件

 设置layout详细信息,点击finish完成创建。

layout File Name :Layout 名字

Root Tag :使用布局样式

在activity_second.XML添加一个按钮控件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn3"android:text="Button3"/></LinearLayout>

 在SecondActivity中添加

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Toast.makeText(SecondActivity.this,"这是第二个界面",Toast.LENGTH_SHORT).show();Button btn3 = findViewById(R.id.btn3);btn3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});}
}

3)使用Intent跳转

        回到FirstActivity,在第一个按钮点击事件中添加

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class FirstActivity extends AppCompatActivity {private Button btn ,btn2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_first);Toast.makeText(FirstActivity.this,"这是第一个界面",Toast.LENGTH_SHORT).show();btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(FirstActivity.this,SecondActivity.class);startActivity(intent);}});btn2 = findViewById(R.id.btn2);btn2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {}});}
}

在SecondActivity,在第三个按钮点击事件中添加

package com.example.helloworld;import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Toast.makeText(SecondActivity.this,"这是第二个界面",Toast.LENGTH_SHORT).show();Button btn3 = findViewById(R.id.btn3);btn3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(SecondActivity.this,FirstActivity.class);startActivity(intent);}});}
}

点击运行,在FirstActivity中点击第一个按钮会进入SecondActivit点击SecondActivitS中的按钮会回到FirstSecond。但是这个时候我们会发现,如果点击返回的话,会回到上个活动界面,因为android 默认为栈的方式,每打开一个界面就会将这个活动压入栈中,点击返回时,将会从顶层逐个出栈。

5)使用intent传递信息

        当使用Intent跳转到另外一个活动时,也可以将一些重要信息传递给下个活动。同时广播也可以使用Intent,暂时先了解。

        修改FirstActivity第一个按钮点击事件

  btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(FirstActivity.this,SecondActivity.class);intent.putExtra("House",1);intent.putExtra("Name","Ryan");startActivity(intent);}});

        修改SecondActivity

package com.example.helloworld;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;
import android.widget.Toast;public class SecondActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Toast.makeText(SecondActivity.this,"这是第二个界面",Toast.LENGTH_SHORT).show();Intent intent = getIntent();int house = intent.getIntExtra("House",-1);Log.d("Test", String.valueOf(house));String str = intent.getStringExtra("Name");Log.d("Test", str);Button btn3 = findViewById(R.id.btn3);btn3.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(SecondActivity.this,FirstActivity.class);startActivity(intent);finish();}});}
}

可以在日志看到成功将信息传递给下一个活动了

五、活动的生命周期

1)活动状态

  每个活动在它的生命周期将会有四个状态

        1.运行状态

        当活动在栈顶的时候,对用户可见时,为运行状态

        2.暂停状态

        当活动不在处于栈顶时,但是仍然可见,这个时候为暂停状态,一般来说,系统不会回收这种状态的活动,

        3.停止状态

        当活动不可见时,就处于停止状态,这个时候如果内存不够的话,系统很有可能回收。

        4.销毁状态

        当活动从栈内出栈的时候,活动就为销毁状态。

2)活动的生命周期

        Android中回调了七个方法,包含了活动的创建到销毁的生命周期

        1.onCreate:活动第一次被创建时调用,在这里可以实现一些初始化操作;

        2.onStart:活动由不可见到可见时调用。

        3.onResum: 活动和用户交互的时候调用,此时活动处于栈顶。

        4.onPause:活动将要启动另外一个活动时调用,在这个函数里面不能进行耗时操作。

        5.onStop:活动由可见到不可见时调用,注意如果是启动一个对话框式,那么onStop不会调用,只会调用onPause;

        6.onDeatroy: 活动被销毁之前调用,并且之后的状态改为销毁状态;

        7.onRestart:活动在停止状态到运行状态之前调用。

        简单来说就是下面三类

        完整生存期:onCreate到onDestroy

        可见生存期:onResum到onPause

        前台生存期:onStart到onStop

3)体验活动的生命周期

        重新创建LifeCycle工程,点击右上角file,新建工程,命名为LifeCycle,具体步骤参考上面。 

        1.创建活动

        在activity_main.xml中添加一个Button一个TextView,这两个控件的操作很相同。宽度都是match_parent表示填充满所占空间。android:layout_height,android:layout_weight,设置高度占比。android:text设置文本。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="10"android:gravity="center"android:text="主界面"/><Buttonandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:id="@+id/btn_1"android:text="打开对话框"/></LinearLayout>

        接下来我们在com.example.lifecycle包上右键添加一个活动,活动名为DialogActivity,点击finish完成创建。

        在activity_dialog.xml也添加一个按钮和一个TextView,并采用LinearLayout布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="center"android:text="对话框"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn_2"android:text="关闭"/></LinearLayout>

        接下来完善主活动和对话框活动的代码,在主活动中我将所有的生命周期都写了出来,在活动进入某个时期时将会回调这个对应的函数。

MainActivity.java

package com.example.lifecycle;import androidx.appcompat.app.AppCompatActivity;import android.content.Context;
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 = "LifeCycleLog";private Context mContext;private Button btn_1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d(TAG, "onCreate: ");mContext = getApplicationContext();btn_1 = findViewById(R.id.btn_1);btn_1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent  = new Intent(MainActivity.this,DialogActivity.class);startActivity(intent);}});}@Overrideprotected void onStart() {super.onStart();Log.d(TAG, "onStart: ");}@Overrideprotected void onResume() {super.onResume();Log.d(TAG, "onResume: ");}@Overrideprotected void onStop() {super.onStop();Log.d(TAG, "onStop: ");}@Overrideprotected void onPause() {super.onPause();Log.d(TAG, "onPause: ");}@Overrideprotected void onRestart(){super.onRestart();Log.d(TAG, "onRestart: ");}@Overrideprotected void onDestroy() {super.onDestroy();Log.d(TAG, "onDestroy: ");}
}

DialogActivity.java

package com.example.lifecycle;import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;public class DialogActivity extends AppCompatActivity {private  Button btn_2;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_dailog);btn_2 = findViewById(R.id.btn_2);btn_2.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {finish();}});}
}

         最重要的一点修改Androidmanifests.xml将对话框活动下添加一句,如不添加这一句,将不显示对话框,显示为完整的活动。

        <activityandroid:name=".DialogActivity"android:theme="@style/Theme.AppCompat.Dialog"/>

        2.运行效果

        现在我们运行程序查看效果,刚点击运行时程序出现主界面时效果如下,

        再点击按钮打开对话框,此时运行效果如下,可以看到当对话框弹出来的时候,活动进入了onPause阶段,此时活动未停止,不进入onStop,若直接打开一个活动完全覆盖主上一个活动则会进入onStop。

        点击对话框的关闭,效果如下,并没有进入onStart.

        现在点击home键,效果如下,界面完全看不到了,活动为停止状态         返回app,效果如下,活动重新启动,活动onResume交互状态

        最后,点击返回键,查看效果,点击返回键相当于finish().

 六、活动的启动模式

        之前我们提到的返回栈的概念就是处于标准模式下,活动出栈入栈的方式。活动总共有四种启动模式:standard,singleTop,singleTask,singleInstance。

1)standard模式

        创建新项目ActivityMode,在activity_main.xml中添加一个按钮。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn"android:text="btn"/></LinearLayout>

        在主活动中完善按钮点击事件,实现方式很奇怪,在点击按钮打开自身,我们先不谈这些,主要着重于standard模式。

package com.example.activitymode;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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d("standard", "onCreate: ");Button btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this,MainActivity.class);startActivity(intent);}});}
}

      现在我们点击运行,再按按钮四次,可以看到如下现象,可以看到onCreate被调用了四次,而且并没有调用onDestroy,所有创建四个实例,现在点击返回按钮,需要一个活动出栈,即需要点击四次才能退出程序。

 

2)singleTop模式

        standard模式下有时候挺让人想不明白,一个活动处于栈顶,为什么返回这个活动还要在创建一个实例呢,能不能让已经处于栈顶时的活动直接打开呢,这就要用到第二种模式singleTop模式了

        继续在ActivityMode项目下修改,在Androidmanifests.xml文件下添加singleTop

         <activityandroid:name=".MainActivity"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>

        现在运行发现无论点多少次也只会创建一个实例。 但是这个模式下,如果活动未处于栈顶启动该活动的话,仍然会创建一个实例。

3)singleTask模式 

        singleTop解决了重复创建栈顶的问题,但是活动不在栈顶还是会创建实例。使用singleTask就会很好的解决这些问题。

        仍然在ActivityMode项目下,再添加一个SecondActivity活动。

activity_second.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:id="@+id/btn2"android:text="btn2"/></LinearLayout>

SecondActivity.java

package com.example.activitymode;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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Log.d("singleTask", "onCreate: ");Button button = findViewById(R.id.btn2);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent i = new Intent(SecondActivity.this,MainActivity.class);startActivity(i);}});}@Overrideprotected  void onDestroy(){super.onDestroy();Log.d("singleTask", "onDestroy: ");}
}

        修改MainActivity.java

package com.example.activitymode;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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d("singleTask", "onCreate:");Button btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this,SecondActivity.class);startActivity(intent);}});}@Overrideprotected  void onDestroy(){super.onDestroy();Log.d("singleTask", "onDestroy: ");}
}

        最后在Androidmanifests.xml修改为singleTask      

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

          现在运行查看现象,可以看到即使不处于栈顶,当返回时也不会再创建新的实例。

4)singleInstance模式

        singleInstance模式简单来说,使用了singleInstance模式的活动是存在于一个独立的返回栈中,

        在ActivityMode项目中添加ThirdActivity活动不需要做什么操作,然后修改SecondActivity活动,点击按钮进入ThirdActivity活动

package com.example.activitymode;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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_second);Log.d("singleInstance:", "SecondActivity:"+String.valueOf(getTaskId()));Button button = findViewById(R.id.btn2);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent i = new Intent(SecondActivity.this,ThirdActivity.class);startActivity(i);}});}@Overrideprotected  void onDestroy(){super.onDestroy();Log.d("singleInstance", "SecondActivity_onDestroy: ");}
}

        修改MainActivity,在onCreate中打印当前的返回栈Id

package com.example.activitymode;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 {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Log.d("singleInstance", "MainActivity:"+String.valueOf(getTaskId()));Button btn = findViewById(R.id.btn);btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(MainActivity.this,SecondActivity.class);startActivity(intent);}});}@Overrideprotected  void onDestroy(){super.onDestroy();Log.d("singleInstance", "onDestroy: ");}
}

        修改Androidmanifests.xml文件,在SecondActivity中添加singleInstance模式

        <activityandroid:name=".ThirdActivity"android:exported="false" /><activityandroid:name=".SecondActivity"android:launchMode="singleInstance"android:exported="false" /><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity>

        现在运行,在MainActivity活动中点击按钮进入SecondActivity,在SecondActivity点击按钮进入ThirdActivity活动,可以在日志如下日志,发现被我们折了singleInstance模式的SecondActivity模式是单独的返回栈Id

        到ThirdActivity活动中,点击系统返回键,发现直接进入了MainActivity活动,再带年纪返回键,又会跑到SecondActivity活动中,在SecondActivity活动中点击返回才可以完全退出程序。因为MainActivity和ThirdActivity处于同一返回栈,当从ThirdActivity返回时,这单独的栈内没有其他的活动,就会从另一返回栈找到栈顶活动返回,此时MainActivity处于栈顶,进而当MainActivity点击返回时,从当前返回栈找到SecondActivity活动,最后再在SecondActivity点击返回键全部活动都出栈,退出程序。

七、小结

        在Android应用开发中,活动(Activity)是至关重要的组件,它负责管理用户界面的呈现和用户与应用程序之间的交互。通过活动,可以创建应用程序的各种界面,包括主屏幕、设置界面、登录界面等,并实现用户与这些界面的交互行为,比如点击按钮、输入文本等。此外,活动还管理着应用程序的生命周期,即从创建到销毁的整个过程中的各个状态变化,开发者可以在不同的生命周期方法中执行相应的操作,例如初始化资源、保存数据、更新UI等。通过返回栈的管理,可以在不同的活动之间进行导航和切换,从而构建出流畅的应用程序导航体验。活动还可以与其他组件进行交互,如通过启动服务来执行后台任务,通过注册广播接收器接收系统事件等。所有,活动的学习与掌握至关重要。

相关文章:

7天入门Android开发之第2天——四大组件之活动

一、活动是什么 活动&#xff08;Activity&#xff09;是 Android 应用程序中的一个重要组件&#xff0c;它代表用户界面上的单个窗口&#xff0c;通常会填充整个屏幕。通过活动&#xff0c;可以创建各种各样的用户界面&#xff0c;并控制界面的行为。活动可以包含各种 UI 元素…...

自然语言(NLP)

It’s time for us to learn how to analyse natural language documents, using Natural Language Processing (NLP). We’ll be focusing on the Hugging Face ecosystem, especially the Transformers library, and the vast collection of pretrained NLP models. Our proj…...

学习java第六十天

Advice的类型&#xff1a; &#xff08;1&#xff09;前置通知&#xff08;Before Advice&#xff09;&#xff1a;在连接点&#xff08;Join point&#xff09;之前执行的通知。 &#xff08;2&#xff09;后置通知&#xff08;After Advice&#xff09;&#xff1a;当连接点退…...

OpenFeign修改HttpClient为Apache HttpClient 5

OpenFeign中http client 如果不做特殊配置&#xff0c;OpenFeign默认使用JDK自带的HttpURLConnection发送HTTP请求&#xff0c; 由于默认HttpURLConnection没有连接池、性能和效率比较低。所以修改为Apache HttpClient 5。 总结为两步&#xff1a; 加依赖改yml 具体操作请往…...

【busybox记录】【shell指令】comm

目录 内容来源&#xff1a; 【GUN】【comm】指令介绍 【busybox】【comm】指令介绍 【linux】【comm】指令介绍 使用示例&#xff1a; 逐行比较两个排序后的文件 - 默认输出 逐行比较两个排序后的文件 - 如果一个文件的排序有问题&#xff0c;那么反错&#xff08;默认&…...

工作中遇到的问题,如何解决的

1. gorm update 一条记录的某个字段后&#xff0c;立刻&#xff08;1ms&#xff09;select这条记录&#xff0c;会有读取不到最新结果的情况&#xff1a; transaction已经提交&#xff0c;数据最后也是更新的。 猜测原因&#xff1a;MySQL没能及时把那条很大的record“刷盘”到…...

数据结构(c):队列

目录 &#x1f37a;0.前言 1.什么是队列 2. 队列的实现 2.1定义队列节点 2.2定义队列 2.3队尾入队列 2.4判断队列是否为空 2.5队头出队列 2.6 队列首元素 2.7队尾元素 2.8队列内的元素个数 2.9销毁队列 3.试运行 &#x1f48e;4.结束语 &#x1f37a;0.前言 言C之…...

Vue单页面应用和多页面应用的区别

概念&#xff1a; SPA单页面应用&#xff08;SinglePage Web Application&#xff09;&#xff0c;指只有一个主页面的应用&#xff0c;一开始只需要加载一次js、css等相关资源。所有内容都包含在主页面&#xff0c;对每一个功能模块组件化。单页应用跳转&#xff0c;就是切换…...

php扩展

查看扩展: print_r(get_loaded_extensions());判断扩展: if (!extension_loaded(gd)) {if (!dl...

mac电脑如何安装python及环境搭建

&#xff08;1&#xff09;进入官网&#xff1a;Download Python | Python.org&#xff0c;根据自己电脑选择python (2)这里我选择的是mac,点击&#xff1a;macos&#xff0c;选择最近版本并点击进入 (3)选择mac版本&#xff1a; (4)点击就可以进入下载&#xff1a; (5)下载好之…...

大数据高级阶段面试题(实时)

1.Kafka的producer如何实现幂等性? ①开启幂等性&#xff0c;将Idempotent设置为true ②将ack设置为-1&#xff0c;确保相同的消息只会发送一次&#xff0c;避免重新发送 2.Kafka的ISR和OSR的作⽤分别是什么? ISR是副本和领导者的数据和状态要保持一致&#xff0c;如果出现…...

Material Studio 计算分子静电力、电荷密度以及差分电荷密度

1.先打开Material Studio导入要计算的分子cif文件或者mol文件&#xff0c;直接Flie-Import 2.高斯几何优化一下结构&#xff0c;参数按照我的设置就行&#xff0c;一般通用&#xff0c;后面出问题再调整 3.点完Run后会跳出很多计算过程&#xff0c;不用管&#xff0c;等他计算完…...

华为鸿蒙系统(Huawei HarmonyOS)

华为鸿蒙系统&#xff08;华为技术有限公司开发的分布式操作系统&#xff09; 华为鸿蒙系统&#xff08;HUAWEI HarmonyOS&#xff09;&#xff0c;是华为公司在2019年8月9日于东莞举行的华为开发者大会&#xff08;HDC.2019&#xff09;上正式发布的分布式操作系统。 华为鸿蒙…...

docker jenkins 部署springboot项目

1、创建jenkins容器 1&#xff0c;首先&#xff0c;我们需要创建一个 Jenkins 数据卷&#xff0c;用于存储 Jenkins 的配置信息。可以通过以下命令创建一个数据卷&#xff1a; docker volume create jenkins_data启动 Jenkins 容器并挂载数据卷&#xff1a; docker run -dit…...

记录一个练手的js逆向password

很明显 请求加密了password 全局搜索 有个加密函数(搜不到的可以搜临近的其他的关键字 或者url参数) 搜索的时候一定要仔细分析 我就没有仔细分析 我搞了好久 又是xhr又是hook的(还没hook到) 我当时也是疏忽了 我寻思这个也不是js文件 直到后来 我怎么也找不到 我就猜想 不…...

如何低成本创建个人网站?

目录 前言 网站源代码 虚拟主机或服务器 域名注册或免费二级域名 域名解析 上传源代码压缩包 添加刚刚的域名 成功搭建 失败的解决方案 结语 前言 很多小白都非常想拥有自己的网站&#xff0c;但很多人虽然有了自己的源代码但苦于不知道怎么将其变成所有人都能够访…...

Finder Windows for Mac:双系统窗口,一键切换!

Finder Windows for Mac是一款专为Mac用户设计的实用工具&#xff0c;它模拟了Windows系统的窗口管理功能&#xff0c;让Mac用户也能享受到类似Windows的窗口操作体验。这款软件的主要功能是提供一个浮动面板&#xff0c;帮助用户随时即时访问打开的Finder窗口列表&#xff0c;…...

Hadoop3:集群搭建及常用命令与shell脚本整理(入门篇,从零开始搭建)

一、集群环境说明 1、用VMware安装3台Centos7.9虚拟机 2、虚拟机配置&#xff1a;2C&#xff0c;2G内存&#xff0c;50G存储 3、集群架构设计 从表格中&#xff0c;可以看出&#xff0c;Hadoop集群&#xff0c;主要有2个模块服务&#xff0c;一个是HDFS服务&#xff0c;一个是…...

yolo-world:”目标检测届大模型“

AI应用开发相关目录 本专栏包括AI应用开发相关内容分享&#xff0c;包括不限于AI算法部署实施细节、AI应用后端分析服务相关概念及开发技巧、AI应用后端应用服务相关概念及开发技巧、AI应用前端实现路径及开发技巧 适用于具备一定算法及Python使用基础的人群 AI应用开发流程概…...

vue3 + ts 快速入门(全)

文章目录 学习链接1. Vue3简介1.1. 性能的提升1.2.源码的升级1.3. 拥抱TypeScript1.4. 新的特性 2. 创建Vue3工程2.1. 基于 vue-cli 创建2.2. 基于 vite 创建&#xff08;推荐&#xff09;vite介绍创建步骤项目结构安装插件项目结构总结 2.3. 一个简单的效果Person.vueApp.vue …...

vue2实现面包屑功能

目录 1. store/index.js 2. router/index.js 3. Header.vue 在Vue 2中实现面包屑导航是一种常见的前端实践&#xff0c;它可以帮助用户了解当前页面在网站结构中的位置&#xff0c;并快速导航到上一级或根目录。以下是使用Vue 2实现面包屑导航的基本步骤&#xff1a; 1. st…...

helm安装 AWS Load Balancer Controller

1、创建AmazonEKSLoadBalancerControllerRole角色 亚马逊文档 创建文档 2&#xff09;、使用 eksctl 创建 IAM 角色 a、安装eksctl eksctl安装文档 使用以下命令下载并提取最新版本的 eksctl curl --silent --location "https://github.com/weaveworks/eksctl/releases/l…...

贪吃蛇大作战(C语言--实战项目)

朋友们&#xff01;好久不见。经过一段时间的沉淀&#xff0c;我这篇文章来和大家分享贪吃蛇大作战这个游戏是怎么实现的。 &#xff08;一&#xff09;.贪吃蛇背景了解及效果展示 首先相信贪吃蛇游戏绝对称的上是我们00后的童年&#xff0c;不仅是贪吃蛇还有俄罗斯⽅块&…...

谷歌确认:链接并不那么重要

谷歌的 Gary Illyes 在最近的一次搜索营销会议上证实&#xff0c;谷歌只需要很少的链接&#xff0c;这为出版商需要关注其他因素提供了越来越多的证据。Gary 在推特上证实了他确实说过这些话。 排名链接的背景 20 世纪 90 年代末&#xff0c;搜索引擎发现链接是验证网站权威性…...

python基础--修饰器

修饰器(语法糖) 在python中函数实际上就是一个对象 def outer(x):def inner(y):return x yreturn innerprint(outer(6)(5))def double(x):return x * 2 def triple(x):return x * 3def calc_number(func, x):print(func(x))calc_number(double, 3) calc_number(triple, 3)函…...

6. Z 字形变换

题目描述 给你一个字符串s和行数numRows&#xff0c;把s字符串按照z字形重新排列。 再从左往右进行读取&#xff0c;返回读取之后的字符串。 本题是找规律&#xff0c;但是没有找出来 解题思路 要想解出来该题&#xff0c;在进行z字变换的时候&#xff0c;我们把字符串的下…...

shell常用文件处理命令

1. 解压 1.1 tar 和 gz 文件 如果你有一个 .tar 文件,你可以使用以下命令来解压: tar -xvf your_file.tar在这个命令中,-x 表示解压缩,-v 表示详细输出(可选),-f 后面跟着要解压的文件名。 如果你的 .tar 文件同时被 gzip 压缩了(即 .tar.gz 文件),你可以使用以下…...

从Paint 3D入门glTF

Paint 3D Microsoft Paint 3D是微软的一款图像编辑软件&#xff0c;它是传统的Microsoft Paint程序的升级版。 这个新版本的Paint专注于三维设计和创作&#xff0c;使用户可以使用简单的工具创建和编辑三维模型。 Microsoft Paint 3D具有直观的界面和易于使用的工具&#xff0…...

数据库(MySQL)—— DQL语句(基本查询和条件查询)

数据库&#xff08;MySQL&#xff09;—— DQL语句&#xff08;基本查询和条件查询&#xff09; 什么是DQL语句基本查询查询多个字段字段设置别名去除重复记录 条件查询语法条件 我们今天进入MySQL的DQL语句的学习&#xff1a; 什么是DQL语句 MySQL中的DQL&#xff08;Data Q…...

如何根据索引删除数组中的元素,并保证删除的正确性

使用 splice() 方法来删除这些索引处的数据 var array [1, 2, 3, 4, 5]; var indexesToDelete [1, 3]; // 需要删除的索引// 将需要删除的索引按照从大到小的顺序排序&#xff0c;以避免删除元素后索引发生变化 indexesToDelete.sort((a, b) > b - a);// 遍历需要删除的索…...

Shell编程规范与变量

目录 一、shell脚本概述 Shell脚本的概念 Shel脚本应用场景 1、shell的作用 2、shell编程规范 Shell脚本的编写 Shell脚本的运行 3、重定向与管道 交互式硬件设备 重定向操作 管道操作符号"|" 二、shell脚本变量 变量的作用 变量的类型 1、自定义变量…...

武汉星起航:策略升级,亚马逊平台销售额持续增长显实力

武汉星起航电子商务有限公司&#xff0c;一家致力于跨境电商领域的企业&#xff0c;于2023年10月30日在上海股权托管交易中心成功挂牌展示&#xff0c;这一里程碑事件标志着公司正式踏入资本市场&#xff0c;开启了新的发展篇章。公司董事长张振邦在接受【第一财经】采访时表示…...

循环链表 -- c语言实现

#pragma once // 带头双向循环链表增删查改实现 #include<stdlib.h> #include<stdio.h> #include<assert.h>typedef int LTDataType;typedef struct ListNode {LTDataType data;struct ListNode* next;struct ListNode* prev; }ListNode;//双链表申请一个新节…...

如何使git提交的时候忽略一些特殊文件?

认识.gitignore文件 在生成远程仓库的时候我们会看到这样一个选项&#xff1a; 这个.gitignore文件有啥用呢&#xff1f; .gotignore文件是Git版本控制系统中的一个特殊文件。用来指定哪些文件或者目录不被Git追踪或者提交到版本库中。也就意味着&#xff0c;如果我们有一些文…...

如何保证Redis双写一致性?

目录 数据不一致问题 数据库和缓存不一致解决方案 1. 先更新缓存&#xff0c;再更新数据 该方案数据不一致的原因 2. 先更新数据库&#xff0c;再更新缓存 3. 先删除缓存&#xff0c;再更新数据库 延时双删 4. 先更新数据库&#xff0c;再删除缓存 该方案数据不一致的…...

HarmonyOS实战开发-如何实现查询当前城市实时天气功能

先来看一下效果 本项目界面搭建基于ArkUI中TS扩展的声明式开发范式&#xff0c; 数据接口是和风&#xff08;天气预报&#xff09;&#xff0c; 使用ArkUI自带的网络请求调用接口。 我想要实现的一个功能是&#xff0c;查询当前城市的实时天气&#xff0c; 目前已实现的功能…...

(三)JSP教程——JSP动作标签

JSP动作标签 用户可以使用JSP动作标签向当前输出流输出数据&#xff0c;进行页面定向&#xff0c;也可以通过动作标签使用、修改和创建对象。 <jsp:include>标签 <jsp:include>标签将同一个Web应用中静态或动态资源包含到当前页面中。资源可以是HTML、JSP页面和文…...

centos7安装真的Redmine-5.1.2+ruby-3.0.0

下载redmine-5.1.2.tar.gz&#xff0c;上传到/usr/local/目录下 cd /usr/local/ tar -zxf redmine-5.1.2.tar.gz cd redmine-5.1.2 cp config/database.yml.example config/database.yml 配置数据连接 #编辑配置文件 vi config/database.yml #修改后的内容如下 product…...

方法的重写

方法的重写 概念&#xff1a;子类继承父类之后&#xff0c;就拥有了符合权限的父类的属性和方法&#xff0c;但是当父类的方法不符合子类的要求的时候&#xff0c;子类也可以重新的书写自己想要的方法。所以&#xff0c;方法的重写&#xff0c;即子类继承父类的方法后&#xf…...

Terraform局部值

Terraform输入变量用于从外部传递值到Terraform模块内部进行使用&#xff0c;如果把Terraform代码看作是一个函数的话&#xff0c;Terraform输入变量就是函数的输入参数。 Terraform局部值则用于在Terraform模块内部定义反复使用的常量值或表达式&#xff0c;如果把Terraform代…...

vue+element-ui实现横向长箭头,横向线上下可自定义文字(使用after伪元素实现箭头)

项目场景&#xff1a; 需要实现一个长箭头&#xff0c;横向线上下可自定义文字 代码描述 <div><span class"data-model">{{ //上方文字}}</span><el-divider class"q"> </el-divider>//分隔线<span class"data-mod…...

性能监控之prometheus+grafana搭建

前言 Prometheus和Grafana是两个流行的开源工具&#xff0c;用于监控和可视化系统和应用程序的性能指标。它们通常一起使用&#xff0c;提供了强大的监控和数据可视化功能。 Prometheus Prometheus是一种开源的系统监控和警报工具包。它最初由SoundCloud开发&#xff0c;并于…...

25-ESP32-S3 内置的真随机数发生器(RNG)

ESP32-S3 内置的真随机数发生器&#xff08;RNG&#xff09;&#x1f60e; 引言 &#x1f4da; 在许多应用中&#xff0c;随机数发生器&#xff08;RNG&#xff09;是必不可少的。无论是在密码学&#x1f512;、游戏&#x1f3ae;、模拟&#x1f9ea;或其他领域&#xff0c;随…...

万兆以太网MAC设计(12)万兆UDP协议栈上板与主机网卡通信

文章目录 一、设置IP以及MAC二、上板效果2.1、板卡与主机数据回环测试2.2、板卡满带宽发送数据 一、设置IP以及MAC 顶层模块设置源MAC地址 module XC7Z100_Top#(parameter P_SRC_MAC 48h01_02_03_04_05_06,parameter P_DST_MAC 48hff_ff_ff_ff_ff_ff )(input …...

2024年4月17日华为春招实习试题【三题】-题目+题解+在线评测,2024.4.17,华为机试

2024年4月17日华为春招实习试题【三题】-题目题解在线评测 &#x1f52e;题目一描述&#xff1a;扑克牌消消乐输入描述输出描述样例一样例二Limitation解题思路一&#xff1a;模拟&#xff0c;遇到连续3张相同牌号的卡牌&#xff0c;直接删除解题思路二&#xff1a;栈解题思路三…...

展开说说:Android线程池解析

何谓线程池&#xff1f;本人理解是存放和管理线程的一个容器。 线程池存在的意义是什么&#xff1f; 第一&#xff1a;前面博客提到过创建和销毁线程的操作本身是有性能开销的&#xff0c;如果把使用的线程对象存起来下次用的时候直接取出来用就省去了一次创建和销毁的成本&a…...

Selenium自动化测试面试题全家桶

&#x1f525; 交流讨论&#xff1a;欢迎加入我们一起学习&#xff01; &#x1f525; 资源分享&#xff1a;耗时200小时精选的「软件测试」资料包 &#x1f525; 教程推荐&#xff1a;火遍全网的《软件测试》教程 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1…...

Docker 容器日志占用空间过大解决办法

1、vi /etc/docker/daemon.json {"log-driver":"json-file","log-opts": {"max-size":"200m", "max-file":"1"} } 2、重新加载守护进程配置文件 systemctl daemon-reload 3、重启docker systemctl…...

update_min_vruntime()流程图

linux kernel scheduler cfs的update_min_vruntime() 看起来还挺绕的。含义其实也简单&#xff0c;总一句话&#xff0c;将 cfs_rq->min_vruntime 设置为&#xff1a; max( cfs_rq->vruntime, min(leftmost_se->vruntime, cfs_rq->curr->vruntime) )。 画个流…...

十进制转任意进制(以及任意进制来回转换<了解>)

十进制转任意进制&#xff1a; #include <iostream> #include <vector> #include <string> using namespace std; // 将十进制数转换为P进制形式的字符串 string toBase(int num, int base) {string result ""; // 初始化结果字符串为空wh…...