【Android】Activity的生命周期

Activity的生命周期

1.返回栈

其实Android是使用任务(task)来管理Activity的,一个任务就是一组存放在栈里的Activity的集合,这个栈也被称作返回栈(back stack)。栈是一种后进先出的数据结构,在默认情况下,每当我们启动了一个新的Activity,它就会在返回栈中入栈,并处于栈顶的位置。而每当我们按下Back键或调用finish()方法去销毁一个Activity时,处于栈顶的Activity就会出栈,前一个入栈的Activity就会重新处于栈顶的位置。系统总是会显示处于栈顶的Activity给用户。

在这里插入图片描述

2.Activity状态

每个Activity在其生命周期中最多可能会有4种状态。

Android Activity 的生命周期是其运行过程中所经历的一系列状态。每个 Activity 在其生命周期中可能会经历以下几种状态:

  1. 活跃状态(运行状态)(Active or Running):
    1. 这是 Activity 的正常运行状态。它处于用户界面的最顶层,并且能够接收用户的输入。
    2. 系统最不愿意回收的就是处于运行状态的Activity,因为这会带来非常差的用户体验。
  2. 暂停状态(Paused):
    1. 当一个新的 Activity 部分遮挡了当前 Activity,或者当前 Activity 调用了 sleep 方法时,它就会进入暂停状态。在这种状态下,Activity 仍然可见,但是无法接收用户输入。
    2. 当一个Activity不再处于栈顶位置,但仍然可见时,Activity就进入了暂停状态。你可能会觉得,既然Activity已经不在栈顶了,怎么会可见呢?这是因为并不是每一个Activity都会占满整个屏幕,比如对话框形式的Activity只会占用屏幕中间的部分区域。处于暂停状态的Activity仍然是完全存活着的,系统也不愿意回收这种Activity(因为它还是可见的,回收可见的东西都会在用户体验方面有不好的影响),只有在内存极低的情况下,系统才会去考虑回收这种Activity。
  3. 停止状态(Stopped):
    1. Activity 被另一个 Activity 完全遮挡时,它就会进入停止状态。在这种状态下,Activity 不再可见,但是它的状态和成员信息仍然被保留。
    2. 系统仍然会为这种Activity保存相应的状态和成员变量,但是这并不是完全可靠的,当其他地方需要内存时,处于停止状态的Activity有可能会被系统回收。
  4. 非可见状态(销毁状态)(Invisible):
    1. 当系统需要为 Activity 显示一个透明的活动,如对话框,或者 Activity 调用了 finish() 方法后,它就会进入非可见状态。在这种状态下,Activity 对用户完全不可见,系统可能会随时将其销毁
    2. 一个Activity从返回栈中移除后就变成了销毁状态。系统最倾向于回收处于这种状态的Activity,以保证手机的内存充足。

3.Activity的生存期

在这里插入图片描述

  1. onCreate(Bundle savedInstanceState):
    1. 这是 Activity 生命周期中的第一个回调方法,用于进行 Activity 的初始化工作。当 Activity 第一次创建时被调用。
    2. 您可以在这里执行一次性的初始化操作,如设置布局和恢复保存的状态。
  2. onStart():
    1. Activity 从停止状态变为可见状态时调用。
    2. 此时 Activity 对用户可见,但还没有进入前台。
  3. onResume():
    1. Activity 进入前台并开始与用户交互时调用。这是 Activity 运行时的活跃状态,可以执行UI更新和用户交互。
  4. onPause():
    1. Activity 部分被另一个 Activity 遮挡,即将失去焦点时调用。这是一个保存当前 Activity 状态的好时机,例如保存用户输入或应用状态。
    2. 我们通常会在这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行速度一定要快,不然会影响到新的栈顶Activity的使用。
  5. onStop():
    1. Activity 不再可见时调用。这可能是因为另一个 Activity 完全覆盖了它,或者 Activity 调用了 finish() 方法。在这个方法中,您应该释放不需要的资源。
  6. onRestart():
    1. Activity 从停止状态恢复到可见状态(运行状态)时调用。这通常发生在 Activity 被另一个 Activity 短暂覆盖后。
  7. onDestroy():
    1. Activity 被销毁时调用。这是一个释放资源和取消注册广播接收器、停止服务等操作的好时机。
  8. onSaveInstanceState(Bundle outState):
    1. 这个方法在 Activity 被系统销毁之前调用,但 Activity 被销毁并不是由于用户操作,如屏幕旋转或配置更改。您可以在这里保存 Activity 的状态,这些状态将在 Activity 重建时通过 onCreate(Bundle savedInstanceState) 方法传递。

在这里插入图片描述

  1. 创建(Creation):
    1. 这个阶段由 onCreate(Bundle savedInstanceState) 方法开始,表示 Activity 正在被创建。如果 Activity 由于配置更改(如屏幕旋转)被系统销毁并重新创建,savedInstanceState 参数将携带之前的状态信息。这个阶段通常用于初始化 Activity,设置布局和恢复状态。
  2. 运行(Active):
    1. 这个阶段包括 onStart()onResume() 两个回调方法。onStart() 表示 Activity 变得可见,但用户可能还不能与之交互。紧接着,onResume() 表示 Activity 已经准备好与用户交互,它现在处于前台并且是活跃状态。
  3. 暂停(Pause):
    1. 这个阶段由 onPause()onStop() 两个回调方法组成。onPause() 表示 Activity 即将失去焦点,但用户不应该在这个时刻保存 Activity 的持久状态,因为这个方法可能会被频繁调用。紧接着,onStop() 表示 Activity 已经不可见,您可以在这个时刻释放不需要的资源。

onRestart() 方法是特殊的,因为它既不与创建阶段对应,也不与运行或暂停阶段对应。它在 Activity 从停止状态变为可见状态时被调用,通常发生在 Activity 被另一个 Activity 短暂覆盖后,或者当 Activity 被系统销毁并需要重新启动时。

在这里插入图片描述

4.Activity被回收了怎么办

前面我们说过,当一个Activity进入了停止状态,是有可能被系统回收的。那么想象以下场景:应用中有一个Activity A,用户在Activity A的基础上启动了Activity B,Activity A就进入了停止状态,这个时候由于系统内存不足,将Activity A回收掉了,然后用户按下Back键返回Activity A,会出现什么情况呢?其实还是会正常显示Activity A的,只不过这时并不会执行onRestart()方法,而是会执行Activity A的onCreate()方法,因为Activity A在这种情况下会被重新创建一次。

这样看上去好像一切正常,可是别忽略了一个重要问题:Activity A中是可能存在临时数据和状态的。打个比方,MainActivity中如果有一个文本输入框,现在你输入了一段文字,然后启动NormalActivity,这时MainActivity由于系统内存不足被回收掉,过了一会你又点击了Back键回到MainActivity,你会发现刚刚输入的文字都没了,因为MainActivity被重新创建了。

如果我们的应用出现了这种情况,是会比较影响用户体验的,所以得想想办法解决这个问题。其实,Activity中还提供了一个onSaveInstanceState()回调方法,这个方法可以保证在Activity被回收之前一定会被调用,因此我们可以通过这个方法来解决问题。

onSaveInstanceState()方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于保存数据,比如可以使用putString()方法保存字符串,使用putInt()方法保存整型数据,以此类推。每个保存方法需要传入两个参数,第一个参数是键,用于后面从Bundle中取值,第二个参数是真正要保存的内容。

@Override
public void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);String tempData = "Something you just typed";outState.putString("data_key", tempData);
}

数据是已经保存下来了,那么我们应该在哪里进行恢复呢?

细心的你也许早就发现,我们一直使用的onCreate()方法其实也有一个Bundle类型的参数。这个参数在一般情况下都是null,但是如果在Activity被系统回收之前,你通过onSaveInstanceState()方法保存数据,这个参数就会带有之前保存的全部数据,我们只需要再通过相应的取值方法将数据取出即可。

修改MainActivity的onCreate()方法,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d(tag, "onCreate");setContentView(R.layout.activity_main);if (savedInstanceState != null) {String tempData = savedInstanceState.getString("data_key");Log.d(tag, "tempData is " + tempData);}
}

使用Bundle保存和取出数据是不是有些似曾相识呢?没错!我们在使用Intent传递数据时也用的类似的方法。这里提醒一点,Intent还可以结合Bundle一起用于传递数据。首先我们可以把需要传递的数据都保存在Bundle对象中,然后再将Bundle对象存放在Intent里。到了目标Activity之后,先从Intent中取出Bundle,再从Bundle中一一取出数据。

8.Activity的启动模式

在实际项目中我们应该根据特定的需求为每个Activity指定恰当的启动模式。

启动模式一共有4种,分别是standard、singleTop、singleTask和singleInstance,可以在AndroidManifest.xml中通过给标签指定android:launchMode属性来选择启动模式。下面我们来逐个进行学习。

standard

standard是Activity默认的启动模式,在不进行显式指定的情况下,所有Activity都会自动使用这种启动模式。到目前为止,我们写过的所有Activity都是使用的standard模式。

经过上一节的学习,你已经知道了Android是使用返回栈来管理Activity的,在standard模式下,每当启动一个新的Activity,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的Activity,系统不会在乎这个Activity是否已经在返回栈中存在,每次启动都会创建一个该Activity的新实例。我们现在通过实践来体会一下standard模式,这次还是在ActivityTest项目的基础上修改。

首先关闭ActivityLifeCycleTest项目,打开ActivityTest项目。修改FirstActivity中onCreate()方法的代码,如下所示:

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d("FirstActivity", this.toString());setContentView(R.layout.first_layout);Button button1 = findViewById(R.id.button1); // 确保你的按钮ID是button1button1.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Intent intent = new Intent(FirstActivity.this, FirstActivity.class);startActivity(intent);}});
}

singleTop

可能在有些情况下,你会觉得standard模式不太合理。Activity明明已经在栈顶了,为什么再次启动的时候还要创建一个新的Activity实例呢?别着急,这只是系统默认的一种启动模式而已,你完全可以根据自己的需要进行修改,比如使用singleTop模式。当Activity的启动模式指定为singleTop,在启动Activity时如果发现返回栈的栈顶已经是该Activity,则认为可以直接使用它,不会再创建新的Activity实例。

我们还是通过实践来体会一下,修改AndroidManifest.xml中FirstActivity的启动模式,如下所示:

    <application ...><activity android:name=".FirstActivity"android:launchMode="singleTop"android:label="This is FirstActivity"><intent-filter><action android:name="android.intent.action.MAIN"/><category android:name="android.intent.category.LAUNCHER"/></intent-filter></activity><!-- 其他活动和组件 --></application>

但是之后不管你点击多少次按钮都不会再有新的打印信息出现,因为目前FirstActivity已经处于返回栈的栈顶,每当想要再启动一个FirstActivity时,都会直接使用栈顶的Activity,因此FirstActivity只会有一个实例,仅按一次Back可以退出程序。不过当FirstActivity并未处于栈顶位置时,再启动FirstActivity还是会创建新的实例的。

下面我们来实验一下,修改FirstActivity中onCreate()方法的代码

这次我们点击按钮后启动的是SecondActivity。然后修改SecondActivity中onCreate()方法的代码

我们在SecondActivity中添加了一行打印日志,并且在按钮点击事件里加入了启动FirstActivity的代码。现在重新运行程序,在FirstActivity界面点击按钮进入SecondActivity,然后在SecondActivity界面点击按钮,又会重新进入FirstActivity。

可以看到系统创建了两个不同的FirstActivity实例,这是由于在SecondActivity中再次启动FirstActivity时,栈顶Activity已经变成了SecondActivity,因此会创建一个新的FirstActivity实例。现在按下Back键会返回到SecondActivity,再次按下Back键又会回到FirstActivity,再按一次Back键才会退出程序。

singleTask

使用singleTop模式可以很好地解决重复创建栈顶Activity的问题,但是正如你在上一节所看到的,如果该Activity并没有处于栈顶的位置,还是可能会创建多个Activity实例的。那么有没有什么办法可以让某个Activity在整个应用程序的上下文中只存在一个实例呢?这就要借助singleTask模式来实现了。当Activity的启动模式指定为singleTask,每次启动该Activity时,系统首先会在返回栈中检查是否存在该Activity的实例,如果发现已经存在则直接使用该实例,并把在这个Activity之上的所有其他Activity统统出栈,如果没有发现就会创建一个新的Activity实例。

我们还是通过代码来更加直观地理解一下。修改AndroidManifest.xml中FirstActivity的启动模式:

<activity android:name=".FirstActivity"android:launchMode="singleTask"android:label="This is FirstActivity"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter>
</activity>

然后在FirstActivity中添加onRestart()方法,并打印日志:Log.d(“FirstActivity”, “onRestart”)

最后在SecondActivity中添加onDestroy()方法,并打印日志:Log.d(“SecondActivity”, “onDestroy”)

其实从打印信息中就可以明显看出,在SecondActivity中启动FirstActivity时,会发现返回栈中已经存在一个FirstActivity的实例,并且是在SecondActivity的下面,于是SecondActivity会从返回栈中出栈,而FirstActivity重新成为了栈顶Activity,因此FirstActivity的onRestart()方法和SecondActivity的onDestroy()方法会得到执行。现在返回栈中只剩下一个FirstActivity的实例了,按一下Back键就可以退出程序。

singleInstance

singleInstance模式应该算是4种启动模式中最特殊也最复杂的一个了,你也需要多花点工夫来理解这个模式。不同于以上3种启动模式,指定为singleInstance模式的Activity会启用一个新的返回栈来管理这个Activity(其实如果singleTask模式指定了不同的taskAffinity,也会启动一个新的返回栈)。

那么这样做有什么意义呢?想象以下场景,假设我们的程序中有一个Activity是允许其他程序调用的,如果想实现其他程序和我们的程序可以共享这个Activity的实例,应该如何实现呢?使用前面3种启动模式肯定是做不到的,因为每个应用程序都会有自己的返回栈,同一个Activity在不同的返回栈中入栈时必然创建了新的实例。而使用singleInstance模式就可以解决这个问题,在这种模式下,会有一个单独的返回栈来管理这个Activity,不管是哪个应用程序来访问这个Activity,都共用同一个返回栈,也就解决了共享Activity实例的问题。

SecondActivity的Task id不同于FirstActivity和ThirdActivity,这说明SecondActivity确实是存放在一个单独的返回栈里的,而且这个栈中只有SecondActivity这一个Activity。

然后我们按下Back键进行返回,你会发现ThirdActivity竟然直接返回到了FirstActivity,再按下Back键又会返回到SecondActivity,再按下Back键才会退出程序,这是为什么呢?

其实原理很简单,由于FirstActivity和ThirdActivity是存放在同一个返回栈里的,当在ThirdActivity的界面按下Back键时,ThirdActivity会从返回栈中出栈,那么FirstActivity就成为了栈顶Activity显示在界面上,因此也就出现了从ThirdActivity直接返回到FirstActivity的情况。然后在FirstActivity界面再次按下Back键,这时当前的返回栈已经空了,于是就显示了另一个返回栈的栈顶Activity,即SecondActivity。最后再次按下Back键,这时所有返回栈都已经空了,也就自然退出了程序。

Activity的最佳实践

知晓当前是在哪一个Activity

这个技巧将教会你如何根据程序当前的界面就能判断出这是哪一个Activity。可能你会觉得挺纳闷的,我自己写的代码怎么会不知道这是哪一个Activity呢?然而现实情况是,在你进入一家公司之后,更有可能的是接手一份别人写的代码,因为你刚进公司就正好有一个新项目启动的概率并不高。阅读别人的代码时有一个很头疼的问题,就是当你需要在某个界面上修改一些非常简单的东西时,却半天找不到这个界面对应的Activity是哪一个。学会了本节的技巧之后,这对你来说就再也不是难题了。

我们还是在ActivityTest项目的基础上修改,首先需要新建一个BaseActivity类。右击com.example.activitytest包→New→Kotlin File/Class,在弹出的窗口中输入BaseActivity,创建类型选择Class

注意,这里的BaseActivity和普通Activity的创建方式并不一样,因为我们不需要让BaseActivity在AndroidManifest.xml中注册,所以选择创建一个普通的类就可以了。然后让BaseActivity继承自AppCompatActivity,并重写onCreate()方法

public class BaseActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);Log.d("BaseActivity", this.getClass().getSimpleName());}
}

我们在onCreate()方法中加了一行日志,用于打印当前实例的类名。我们先是获取了当前实例的Class对象,然后再调用simpleName获取当前实例的类名。

接下来我们需要让BaseActivity成为ActivityTest项目中所有Activity的父类

修改FirstActivity、SecondActivity和ThirdActivity的继承结构,让它们不再继承自AppCompatActivity,而是继承自BaseActivity。而由于BaseActivity又是继承自AppCompatActivity的,所以项目中所有Activity的现有功能并不受影响,它们仍然继承了Activity中的所有特性。现在重新运行程序,然后通过点击按钮分别进入FirstActivity、SecondActivity和ThirdActivity的界面,这时观察Logcat中的打印信息

现在每当我们进入一个Activity的界面,该Activity的类名就会被打印出来,这样我们就可以时刻知晓当前界面对应的是哪一个Activity了。

随时随地退出程序

如果目前你手机的界面还停留在ThirdActivity,你会发现当前想退出程序是非常不方便的,需要连按3次Back键才行。按Home键只是把程序挂起,并没有退出程序。如果我们的程序需要注销或者退出的功能该怎么办呢?看来要有一个随时随地都能退出程序的方案才行。其实解决思路也很简单,只需要用一个专门的集合对所有的Activity进行管理就可以了。

下面我们就来实现一下。新建一个单例类ActivityCollector作为Activity的集合,代码如下所示

public class ActivityCollector {private static ActivityCollector instance;private ArrayList<Activity> activities;private ActivityCollector() {activities = new ArrayList<>();}public static synchronized ActivityCollector getInstance() {if (instance == null) {instance = new ActivityCollector();}return instance;}public void addActivity(Activity activity) {activities.add(activity);}public void removeActivity(Activity activity) {activities.remove(activity);}public void finishAll() {for (Activity activity : activities) {if (!activity.isFinishing()) {activity.finish();}}activities.clear();}
}

这里使用了单例类,是因为全局只需要一个Activity集合。

在集合中,我们通过一个ArrayList来暂存Activity,然后提供了一个addActivity()方法,用于向ArrayList中添加Activity;

提供了一个removeActivity()方法,用于从ArrayList中移除Activity;

最后提供了一个finishAll()方法,用于将ArrayList中存储的Activity全部销毁。

注意在销毁Activity之前,我们需要先调用activity.isFinishing来判断Activity是否正在销毁中,因为Activity还可能通过按下Back键等方式被销毁,如果该Activity没有正在销毁中,我们再去调用它的finish()方法来销毁它。

修改BaseActivity中的代码

public class ActivityCollector {private static ActivityCollector instance;private List<Activity> activities = new ArrayList<>();private ActivityCollector() {}public static synchronized ActivityCollector getInstance() {if (instance == null) {instance = new ActivityCollector();}return instance;}public void addActivity(Activity activity) {activities.add(activity);}public void removeActivity(Activity activity) {activities.remove(activity);}public void finishAll() {for (Activity activity : activities) {if (!activity.isFinishing()) {activity.finish();}}activities.clear();}
}

在BaseActivity的onCreate()方法中调用了ActivityCollector的addActivity()方法,表明将当前正在创建的Activity添加到集合里。

然后在BaseActivity中重写onDestroy()方法,并调用了ActivityCollector的removeActivity()方法,表明从集合里移除一个马上要销毁的Activity。

从此以后,不管你想在什么地方退出程序,只需要调用ActivityCollector.finishAll()方法就可以

android.os.Process.killProcess(android.os.Process.myPid())

killProcess()方法用于杀掉一个进程,它接收一个进程id参数,我们可以通过myPid()方法来获得当前程序的进程id。需要注意的是,killProcess()方法只能用于杀掉当前程序的进程,不能用于杀掉其他程序。

启动Activity的最佳写法

启动Activity的方法相信你已经非常熟悉了,

首先通过Intent构建出当前的“意图”,

然后调用startActivity()或startActivityForResult()方法将Activity启动起来,

如果有数据需要在Activity之间传递,也可以借助Intent来完成。

在真正的项目开发中经常会出现对接的问题。比如SecondActivity并不是由你开发的,但现在你负责开发的部分需要启动SecondActivity,而你却不清楚启动SecondActivity需要传递哪些数据。

这时无非就有两个办法:一个是你自己去阅读SecondActivity中的代码,另一个是询问负责编写SecondActivity的同事。你会不会觉得很麻烦呢?其实只需要换一种写法,就可以轻松解决上面的窘境。修

改SecondActivity中的代码,如下所示:

public class SecondActivity extends BaseActivity {public static void actionStart(Context context, String data1, String data2) {Intent intent = new Intent(context, SecondActivity.class);intent.putExtra("param1", data1); // 修复了方括号为正常字符intent.putExtra("param2", data2);context.startActivity(intent);}
}

我们在SecondActivity 中添加了一个actionstart()方法,在这个方法中完成了Intent的构建,

另外所有SecondActivity中需要的数据都是通过actionStart()方法的参数传递过来的,然后把它们存储到Intent中,最后调用 startActivity()方法启动 SecondActivity。

现在只需要一行代码就可以启动SecondActivity

button1.setOnClickListener { SecondActivity.actionStart(this, "data1", "data2") }context.startActivity(intent);}
}

我们在SecondActivity 中添加了一个actionstart()方法,在这个方法中完成了Intent的构建,

另外所有SecondActivity中需要的数据都是通过actionStart()方法的参数传递过来的,然后把它们存储到Intent中,最后调用 startActivity()方法启动 SecondActivity。

现在只需要一行代码就可以启动SecondActivity

button1.setOnClickListener { SecondActivity.actionStart(this, "data1", "data2") }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/48542.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AES算法概述

文章目录 一、AES 概述二、AES 加密算法的特点三、秘钥类型四、填充方式五、加密方式 一、AES 概述 二、AES 加密算法的特点 AES加密的数据块长度为128&#xff08;16字节&#xff09;&#xff0c;长度不足需要填充。密码长度可以为16,24,32字节。 三、秘钥类型 AES加密按秘…

【C++高阶】精通AVL树:全面剖析与深度学习

目录 &#x1f680; 前言一&#xff1a; &#x1f525; AVL树的性质二&#xff1a; &#x1f525; AVL树节点的定义三&#xff1a; &#x1f525; AVL树的插入四&#xff1a; &#x1f525; AVL树的平衡调整&#xff08;附动图&#xff09; 五&#xff1a;&#x1f525; AVL树的…

c++初阶篇(三):内联函数及auto关键字

1.内联函数 1.1 概念 以inline修饰的函数叫做内联函数&#xff0c;编译时C编译器会在调用内联函数的地方展开&#xff0c;没有函数调 用建立栈帧的开销&#xff0c;内联函数提升程序运行的效率。 如果在上述函数前增加 inline 关键字将其改成内联函数&#xff0c;在编译期间编…

RNN循环递归网络讲解与不掉包python实现

这里写目录标题 1.算法简介2. RNN算法原理2.1 RNN基本结构介绍2.2 计算流程 3.完整训练代码 1.算法简介 参考论文&#xff1a;Elman J L. Finding structure in time[J]. Cognitive science, 1990, 14(2): 179-211.&#xff0c;谷歌被引次数超16000! 说到循环递归结构就不得不…

秒杀案例-分布式锁Redisson、synchronized、RedLock

模拟秒杀 源码地址前期准备创建数据库表导入数据dependenciespomControllerTSeckillProductTseckillProductServiceTseckillProductServiceImplTseckillProductMapperTseckillProductMapper.xml使用JMeter压力测试开始测试超卖现象原因解决办法更改数据库库存500进行JMeter压力…

运维锅总详解Kubernetes之Kubelet

本文尝试从Kubelet的发展历史、实现原理、交互逻辑、伪代码实现及最佳实践5个方面对Kubelet进行详细阐述。希望对您有所帮助&#xff01; 一、kubelet发展历史 Kubelet 是 Kubernetes 中的核心组件之一&#xff0c;负责管理单个节点上的容器运行。它的发展历史和功能演进是 Kub…

【LeetCode】222. 完全二叉树的个数

什么是计算机基础&#xff1f;如果本题能够用二分二进制二叉树的方式解出本题&#xff0c;那么我可以认为你的计算机基础就很好了。很久以来&#xff0c;我一直认为自己的计算机基础好&#xff0c;但是自刷题以来&#xff0c;跟网上这么多优秀的同学相比&#xff0c;我发现我实…

五分钟学会 Docker Registry 搭建私有镜像仓库

在上一篇文章《前端不懂 Docker &#xff1f;先用它换掉常规的 Vue 项目部署方式》中&#xff0c;我们学习了如何使用 aliyun 私有镜像仓库&#xff0c;也了解到可以使用 Docker Registry 搭建私有镜像仓库。这篇文章就分享下实操过程。 registry 是官方提供的 registry 镜像&…

WEB前端09-前端服务器搭建(Node.js/nvm/npm)

前端服务器的搭建 在本文中&#xff0c;我们将介绍如何安装和配置 nvm&#xff08;Node Version Manager&#xff09;以方便切换不同版本的 Node.js&#xff0c;以及如何设置 npm&#xff08;Node Package Manager&#xff09;使用国内镜像&#xff0c;并搭建一个简单的前端服…

类和对象(三)

默认成员函数 接下来继续看剩下的两个默认成员函数。 const成员函数 将const修饰的成员函数称之为const成员函数&#xff0c;const修饰成员函数放到成员函数参数列表的后 ⾯。const实际修饰该成员函数隐含的this指针&#xff0c;表明在该成员函数中不能对类的任何成员进⾏修…

秋招突击——7/17——复习{二分查找——搜索插入位置、搜索二维矩阵,}——新作{链表——反转链表和回文链表,子串——和为K的子数组}

文章目录 引言新作二分模板二分查找——搜索插入位置复习实现 搜索二维矩阵复习实现 新作反转链表个人实现参考实现 回文链表个人实现参考实现 和为K的子数组个人实现参考实现 总结 引言 今天算法得是速通的&#xff0c;严格把控好时间&#xff0c;后面要准备去面试提前批了&a…

C语言实例-约瑟夫生者死者小游戏

问题&#xff1a; 30个人在一条船上&#xff0c;超载&#xff0c;需要15人下船。于是人们排成一队&#xff0c;排队的位置即为他们的编号。报数&#xff0c;从1开始&#xff0c;数到9的人下船&#xff0c;如此循环&#xff0c;直到船上仅剩15人为止&#xff0c;问都有哪些编号…

C语言 | Leetcode C语言题解之第260题只出现一次的数字III

题目&#xff1a; 题解&#xff1a; int* singleNumber(int* nums, int numsSize, int* returnSize) {int xorsum 0;for (int i 0; i < numsSize; i) {xorsum ^ nums[i];}// 防止溢出int lsb (xorsum INT_MIN ? xorsum : xorsum & (-xorsum));int type1 0, type2…

【Mysql】Docker下Mysql8数据备份与恢复

[TOC] 【Mysql】Docker下Mysql8数据备份与恢复 1 创建Mysql容器 格式 docker run -d --name容器名称 -p 宿主端口号:3306 -e MYSQL_ROOT_PASSWORDmysql密码 -e MYSQL_PASSWORDmysql密码 -e TZAsia/Shanghai -v 宿主目录-数据:/var/lib/mysql -v 宿主目录-备份数据:/back…

多态性概念 OOPS

大家好&#xff01;今天&#xff0c;我们将探讨面向对象编程 (OOP) 中的一个基本概念 - 多态性。具体来说&#xff0c;我们将重点介绍其三种主要形式&#xff1a;方法重载、方法覆盖和方法隐藏。对于任何使用 OOP 语言&#xff08;例如 C#&#xff09;的程序员来说&#xff0c;…

NET 语言识别,语音控制操作、语音播报

System.Speech. 》》System.Speech.Synthesis; 语音播报 》》System.Speech.Recognition 语音识别 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Speech.Recog…

mac二进制安装operator-sdk

0. 前置条件 1. 安装go 安装步骤略。 1. 下载operator-sdk源码包 https://github.com/operator-framework/operator-sdk 1.1 选择适合当前go版本的operator版本&#xff0c;在operator-sdk/go.mod文件中可以查看Operator-sdk使用的go版本。 2. 编译 源码包下载后&#x…

C语言航空售票系统

以下是系统部分页面 以下是部分源码&#xff0c;需要源码的私信 #include<stdio.h> #include<stdlib.h> #include<string.h> #define max_user 100 typedef struct ft {char name[50];//名字char start_place[50];//出发地char end_place[50];//目的地char …

JAVA 异步编程(线程安全)二

1、线程安全 线程安全是指你的代码所在的进程中有多个线程同时运行&#xff0c;而这些线程可能会同时运行这段代码&#xff0c;如果每次运行的代码结果和单线程运行的结果是一样的&#xff0c;且其他变量的值和预期的也是一样的&#xff0c;那么就是线程安全的。 一个类或者程序…

多线程初阶(二)- 线程安全问题

目录 1.观察count 原因总结 2.解决方案-synchronized关键字 &#xff08;1&#xff09;synchronized的特性 &#xff08;2&#xff09;如何正确使用 语法格式 3.死锁 &#xff08;1&#xff09;造成死锁的情况 &#xff08;2&#xff09;死锁的四个必要条件 4.Java标准…