Activity 生命周期阶段

1. 开始之前

在本 Codelab 中,您将了解 Android 的一个基础部分:Activity 生命周期

在 Activity 的生命周期内,它会在各种状态之间转换,有时也会回到之前的状态。这种状态之间的转换称为 Activity 生命周期。

在 Android 中,Activity 是与用户互动的主要入口点。

过去,一个 Activity 在应用中显示一个屏幕。根据当前的最佳实践,一个 Activity 可以通过根据需要切换屏幕来显示多个屏幕。

Activity 生命周期从 Activity 的创建开始,到其销毁结束,系统会在销毁时回收该 Activity 的资源。当用户进入或离开 Activity 时,每个 Activity 都会在 Activity 生命周期的不同状态之间转换。

作为 Android 开发者,您需要了解 Activity 生命周期。如果您的 Activity 未能正确响应生命周期状态变化,您的应用可能会产生奇怪的错误、给用户带来困惑的行为,或者占用过多的 Android 系统资源。理解 Android 生命周期并正确响应生命周期状态变化是 Android 开发的重要组成部分。

前提条件

  • 了解 Activity 是什么以及如何在应用中创建 Activity
  • 了解 Activity 的 onCreate() 方法的作用以及在该方法中执行的操作类型

您将学到什么

  • 如何将日志信息打印到 Logcat
  • Activity 生命周期的基础知识以及当 Activity 在状态之间移动时调用的回调
  • 如何重写生命周期回调方法以在 Activity 生命周期的不同时间执行操作

您将构建什么

  • 修改入门应用 Dessert Clicker,添加在 Logcat 中显示的日志信息。
  • 重写生命周期回调方法并记录 Activity 状态的变化。
  • 运行应用,注意 Activity 启动、停止和恢复时出现的日志信息。
  • 实现 rememberSaveable 以保留设备配置发生变化时可能丢失的应用数据。

2. 应用概览

在本 Codelab 中,您将使用一个名为 Dessert Clicker 的入门应用。在 Dessert Clicker 中,用户每次点按屏幕上的甜点时,应用都会为用户“购买”该甜点。应用会更新布局中的值,用于显示

  • “购买”的甜点数量
  • “购买”甜点的总收入

245d0bdfc09f4d54.png

此应用包含与 Android 生命周期相关的几个错误。例如,在某些情况下,应用会将甜点值重置为 0。了解 Android 生命周期将帮助您理解这些问题发生的原因以及如何解决它们。

下载入门代码

在 Android Studio 中,打开 basic-android-kotlin-compose-training-dessert-clicker 文件夹。

3. 探索生命周期方法并添加基本日志记录

每个 Activity 都有所谓的生命周期。这个术语是引用动植物生命周期,比如蝴蝶的生命周期——蝴蝶的不同状态显示了它从卵到毛毛虫到蛹到蝴蝶再到死亡的成长过程。

Butterfly Lifecycle - growth from egg to caterpillar to pupa to butterfly to death.

类似地,Activity 生命周期包含 Activity 可以经历的不同状态,从 Activity 首次初始化到其销毁,此时操作系统 (OS) 会回收其内存。通常,程序的入口点是 main() 方法。然而,Android Activity 从 onCreate() 方法开始;这个方法相当于上面例子中的卵阶段。您在本课程中已经多次使用过 Activity,您可能已经认识 onCreate() 方法。当用户启动您的应用、在 Activity 之间导航、在应用内部和外部导航时,Activity 会改变状态。

下图显示了所有 Activity 生命周期状态。顾名思义,这些状态代表 Activity 的状态。请注意,与蝴蝶生命周期不同,Activity 在其整个生命周期中可以在状态之间来回切换,而不仅仅是朝一个方向移动。

ca808edb1c95f07a.png

通常,当 Activity 生命周期状态发生变化时,您会希望改变某些行为或运行某些代码。因此,Activity 类本身以及 Activity 的任何子类(例如 ComponentActivity)都实现了一组生命周期回调方法。当 Activity 从一个状态转换到另一个状态时,Android 会调用这些回调,您可以在自己的 Activity 中重写这些方法,以响应这些生命周期状态变化来执行任务。下图显示了生命周期状态以及可用的可重写回调。

The Activity Lifecycle scheme

了解 Android 何时调用可重写的回调以及在每个回调方法中做什么很重要,但这两个图都很复杂,可能会令人困惑。在本 Codelab 中,您将不再只是阅读每个状态和回调的含义,而是要进行一些侦探工作,并建立您对 Android Activity 生命周期的理解。

第 1 步:检查 onCreate() 方法并添加日志记录

为了弄清楚 Android 生命周期发生了什么,了解何时调用各种生命周期方法很有帮助。这些信息可以帮助您确定 Dessert Clicker 应用中哪里出现了问题。

确定此信息的一种简单方法是使用 Android 日志记录功能。日志记录使您能够在应用运行时向控制台写入短消息,并使用它来查看何时触发了不同的回调。

  1. 运行 Dessert Clicker 应用,多次点按甜点图片。注意 Desserts sold 的值和总金额如何变化。
  2. 打开 MainActivity.kt 并检查此 Activity 的 onCreate() 方法
override fun onCreate(savedInstanceState: Bundle?) {
    // ...
}

在 Activity 生命周期图中,您可能认识 onCreate() 方法,因为您之前使用过此回调。这是每个 Activity 都必须实现的方法。onCreate() 方法是您应该对 Activity 进行一次性初始化的位置。例如,在 onCreate() 中,您会调用 setContent() 来指定 Activity 的 UI 布局。

The onCreate Lifecycle method

onCreate() 生命周期方法只调用一次,就在 Activity 初始化之后——当操作系统在内存中创建新的 Activity 对象时。在 onCreate() 执行后,该 Activity 被视为处于创建状态。

  1. 将以下常量添加到 MainActivity.kt 文件的顶层,即 class MainActivity 类声明的上方。

一个好的约定是在文件中声明一个 TAG 常量,因为它的值不会改变。

要将其标记为编译时常量,请在声明变量时使用 const。编译时常量是在编译期间已知的值。

private const val TAG = "MainActivity"
  1. onCreate() 方法中,紧跟在调用 super.onCreate() 之后,添加以下行
Log.d(TAG, "onCreate Called")
  1. 如果需要,导入 Log 类(按下 Alt+Enter,或者在 Mac 上按下 Option+Enter,然后选择 Import)。如果您启用了自动导入,这应该会自动发生。
import android.util.Log

Log 类将消息写入 LogcatLogcat 是用于日志消息的控制台。来自 Android 关于您的应用的消息会在此处显示,包括您使用 Log.d() 方法或其他 Log 类方法明确发送到日志的消息。

Log 指令有三个重要方面

  • 日志消息的优先级,即消息的重要性。在本例中,Log.v() 记录详细消息。Log.d() 方法写入调试消息。Log 类中的其他方法包括用于信息消息的 Log.i()、用于警告的 Log.w() 以及用于错误消息的 Log.e()
  • 日志 tag(第一个参数),在本例中为 "MainActivity"。标签是一个字符串,可让您更轻松地在 Logcat 中找到您的日志消息。标签通常是类的名称。
  • 实际的日志消息,称为 msg(第二个参数),是一个短字符串,在本例中为 "onCreate Called"

a4ff4aa74384ff6.png

  1. 编译并运行 Dessert Clicker 应用。当您点按甜点时,应用中不会看到任何行为差异。在 Android Studio 中,屏幕底部,点击 Logcat 标签页。

cedcce52592c6665.png

  1. Logcat 窗口中,在搜索字段中输入 tag:MainActivity

37080c4e00561b0.png

Logcat 可能包含许多消息,其中大部分对您没有用。您可以通过多种方式过滤 Logcat 条目,但搜索是最简单的方法。由于您在代码中使用了 MainActivity 作为日志标签,因此可以使用该标签来过滤日志。您的日志消息包括日期和时间、您的日志标签、包名 (com.example.dessertclicker) 和实际消息。由于此消息出现在日志中,您就知道 onCreate() 已执行。

第 2 步:实现 onStart() 方法

onStart() 生命周期方法紧随 onCreate() 之后调用。在 onStart() 运行后,您的 Activity 在屏幕上可见。与仅调用一次来初始化 Activity 的 onCreate() 不同,系统可以在 Activity 的生命周期中多次调用 onStart()

a357d2291de472d9.png

请注意,onStart() 与相应的 onStop() 生命周期方法配对。如果用户启动您的应用然后返回设备的主屏幕,Activity 将停止并且不再在屏幕上可见。

  1. 在 Android Studio 中,打开 MainActivity.kt 并将光标置于 MainActivity 类中,选择 Code > Override Methods... 或按下 Control+O。将出现一个对话框,其中包含您可以重写此类的所有方法的长列表。

20c34cbad8dce892.png

  1. 开始输入 onStart 以搜索正确的方法。要滚动到下一个匹配项,请使用向下箭头。从列表中选择 onStart() 并点击 OK 以插入模板重写代码。代码示例如下:
override fun onStart() {
    super.onStart()
}
  1. onStart() 方法内部,添加日志消息
override fun onStart() {
    super.onStart()
    Log.d(TAG, "onStart Called")
}
  1. 编译并运行 Dessert Clicker 应用,然后打开 Logcat 窗格。
  2. 在搜索字段中输入 tag:MainActivity 以过滤日志。请注意,onCreate()onStart() 方法按顺序调用,并且您的 Activity 在屏幕上可见。
  3. 按下设备上的 Home 按钮,然后使用最近任务屏幕返回到 Activity。注意 Activity 会从中断处恢复,所有值都相同,并且 onStart() 第二次记录到 Logcat 中。同时注意 onCreate() 方法没有再次调用。
2024-04-26 14:54:48.721  5386-5386  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 14:54:48.756  5386-5386  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 14:55:41.674  5386-5386  MainActivity            com.example.dessertclicker           D  onStart Called

第 3 步:添加更多日志语句

在此步骤中,您将为所有其他生命周期方法实现日志记录。

  1. 在您的 MainActivity 中重写其余的生命周期方法,并为每个方法添加日志语句,如以下代码所示:
override fun onResume() {
    super.onResume()
    Log.d(TAG, "onResume Called")
}

override fun onRestart() {
    super.onRestart()
    Log.d(TAG, "onRestart Called")
}

override fun onPause() {
    super.onPause()
    Log.d(TAG, "onPause Called")
}

override fun onStop() {
    super.onStop()
    Log.d(TAG, "onStop Called")
}

override fun onDestroy() {
    super.onDestroy()
    Log.d(TAG, "onDestroy Called")
}
  1. 再次编译并运行 Dessert Clicker,然后检查 Logcat。

请注意,这次除了 onCreate()onStart() 之外,还有 onResume() 生命周期回调的日志消息。

2024-04-26 14:56:48.684  5484-5484  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 14:56:48.709  5484-5484  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 14:56:48.713  5484-5484  MainActivity            com.example.dessertclicker           D  onResume Called

当 Activity 从头开始启动时,您会按顺序看到这三个生命周期回调被调用

  • 系统创建应用时调用 onCreate()
  • onStart() 使应用在屏幕上可见,但用户尚无法与其互动。
  • onResume() 将应用带到前台,用户现在可以与其互动。

尽管名称如此,onResume() 方法在启动时就会调用,即使没有任何东西需要恢复。

The Activity Lifecycle scheme

4. 探索生命周期用例

现在您已经为 Dessert Clicker 应用设置了日志记录,您就可以开始使用该应用并探索生命周期回调如何触发了。

用例 1:打开和关闭 Activity

您从最基本的用例开始,即第一次启动应用然后关闭应用。

  1. 编译并运行 Dessert Clicker 应用(如果尚未运行)。如您所见,当 Activity 第一次启动时,会调用 onCreate()onStart()onResume() 回调。
2024-04-26 14:56:48.684  5484-5484  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 14:56:48.709  5484-5484  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 14:56:48.713  5484-5484  MainActivity            com.example.dessertclicker           D  onResume Called
  1. 点按几下纸杯蛋糕。
  2. 点按设备上的 Back 按钮。

在 Logcat 中注意 onPause()onStop() 按该顺序调用。

2024-04-26 14:58:19.984  5484-5484  MainActivity            com.example.dessertclicker           D  onPause Called
2024-04-26 14:58:20.491  5484-5484  MainActivity            com.example.dessertclicker           D  onStop Called
2024-04-26 14:58:20.517  5484-5484  MainActivity            com.example.dessertclicker           D  onDestroy Called

在这种情况下,使用 Back 按钮会导致 Activity(和应用)从屏幕上移除,并移至 Activity 堆栈的后面。

如果您的代码手动调用 Activity 的 finish() 方法,或者用户强制退出应用,Android OS 可能会关闭您的 Activity。例如,用户可以在最近任务屏幕中强制退出或关闭应用。如果您的应用长时间未在屏幕上显示,操作系统也可能自行关闭您的 Activity。Android 这样做是为了节省电池电量并回收应用使用的资源,以便其他应用可以使用。这些只是 Android 系统销毁您的 Activity 的几个示例。在其他情况下,Android 系统会在不提供警告的情况下销毁您的 Activity。

用例 2:离开 Activity 并返回

现在您已经启动并关闭了应用,您已经看到了 Activity 第一次创建时的大多数生命周期状态。您也看到了 Activity 关闭时经历的大多数生命周期状态。但是当用户与 Android 设备互动时,他们会在应用之间切换、返回主屏幕、启动新应用,并处理其他 Activity(例如电话呼叫)的中断。

您的 Activity 不会每次用户离开该 Activity 时就完全关闭

  • 当您的 Activity 不再在屏幕上可见时,这种状态称为将 Activity 置于后台。与此相反的是 Activity 处于前台或屏幕上可见时。
  • 当用户返回到您的应用时,同一个 Activity 会重新启动并再次变得可见。这部分生命周期称为应用的可见生命周期。

当您的应用处于后台时,通常不应主动运行以节省系统资源和电池电量。您可以使用 Activity 生命周期及其回调来了解您的应用何时移动到后台,以便您可以暂停任何正在进行的操作。然后,当您的应用回到前台时,重新启动这些操作。

在此步骤中,您将了解应用进入后台并再次返回前台时的 Activity 生命周期。

  1. 运行 Dessert Clicker 应用,点按几次纸杯蛋糕。
  2. 按下设备上的 Home 按钮,并在 Android Studio 中观察 Logcat。返回主屏幕会将您的应用置于后台,而不是完全关闭应用。请注意,调用了 onPause()onStop() 方法。
2024-04-26 15:00:04.905  5590-5590  MainActivity            com.example.dessertclicker           D  onPause Called
2024-04-26 15:00:05.430  5590-5590  MainActivity            com.example.dessertclicker           D  onStop Called

调用 onPause() 时,应用不再具有焦点。在 onStop() 之后,应用不再在屏幕上可见。虽然 Activity 已停止,但 Activity 对象仍然在后台内存中。Android OS 并未销毁该 Activity。用户可能会返回到应用,因此 Android 会保留您的 Activity 资源。

c470ee28ab7f8a1a.png

  1. 使用最近任务屏幕返回到应用。在模拟器上,可以通过下图所示的方形系统按钮访问最近任务屏幕。

在 Logcat 中注意,Activity 通过 onRestart()onStart() 重新启动,然后通过 onResume() 恢复。

bc156252d977e5ae.png

2024-04-26 15:00:39.371  5590-5590  MainActivity            com.example.dessertclicker           D  onRestart Called
2024-04-26 15:00:39.372  5590-5590  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 15:00:39.374  5590-5590  MainActivity            com.example.dessertclicker           D  onResume Called

当 Activity 返回前台时,onCreate() 方法不再调用。Activity 对象没有被销毁,因此不需要再次创建。代わりに调用 onRestart() 方法。注意,这次当 Activity 返回前台时,Desserts sold 数量得到了保留。

  1. 至少启动一个除了 Dessert Clicker 之外的应用,以便设备在最近任务屏幕中有几个应用。
  2. 调出最近任务屏幕并打开另一个最近的 Activity。然后返回最近任务应用并将 Dessert Clicker 重新带回前台。

注意,在这里您在 Logcat 中看到的与按下 Home 按钮时看到的回调相同。应用进入后台时调用 onPause()onStop(),然后当它回来时调用 onRestart()onStart()onResume()

这些方法在应用停止并进入后台或应用重新启动并返回前台时调用。如果您需要在这些情况下在应用中执行某些工作,则重写相关的生命周期回调方法。

用例 3:部分隐藏 Activity

您已经了解到,当应用启动并调用 onStart() 时,应用会在屏幕上可见。当调用 onResume() 时,应用获得用户焦点——即用户可以与应用互动。应用完全显示在屏幕上并具有用户焦点的生命周期部分称为前台生命周期

当应用进入后台时,在 onPause() 之后失去焦点,在 onStop() 之后应用不再可见。

焦点和可见性之间的区别很重要。Activity 可以部分在屏幕上可见,但没有用户焦点。在此步骤中,您将查看 Activity 部分可见但没有用户焦点的一种情况。

  1. 运行 Dessert Clicker 应用,点击屏幕右上角的 Share 按钮。

共享 Activity 出现在屏幕下半部分,但 Activity 在上半部分仍然可见。

677c190d94e57447.pngca6285cbbe3801cf.png

  1. 检查 Logcat,注意只有 onPause() 被调用。
2024-04-26 15:01:49.535  5590-5590  MainActivity            com.example.dessertclicker           D  onPause Called

在此用例中,onStop() 未调用,因为 Activity 仍然部分可见。但 Activity 没有用户焦点,用户无法与其互动——前台的“分享”Activity 具有用户焦点。

为什么这种差异很重要?只有 onPause() 的中断通常只持续很短的时间,然后就会返回您的 Activity 或导航到另一个 Activity 或应用。您通常希望保持 UI 更新,以免应用的其余部分显得冻结。

onPause() 中运行的任何代码都会阻止其他内容的显示,因此请保持 onPause() 中的代码轻量。例如,如果有电话呼入,onPause() 中的代码可能会延迟来电通知。

  1. 点击分享对话框外部以返回应用,注意 onResume() 被调用。

onResume()onPause() 都与焦点有关。onResume() 方法在 Activity 获得焦点时调用,而 onPause() 在 Activity 失去焦点时调用。

5. 探索配置变更

在管理 Activity 生命周期时,还有一个重要的用例需要理解:配置变更如何影响 Activity 的生命周期。

当设备状态发生根本性变化时,会发生配置变更,系统解决此变更最简单的方式是完全关闭并重建 Activity。例如,如果用户更改设备语言,整个布局可能需要更改以适应不同的文本方向和字符串长度。如果用户将设备插入底座或添加物理键盘,应用布局可能需要利用不同的显示尺寸或布局。如果设备方向发生变化——如果设备从纵向旋转到横向或反之——布局可能需要更改以适应新的方向。让我们看看应用在这种情况下如何表现。

最后一个要演示的生命周期回调是 onDestroy(),它在 onStop() 之后调用。它在 Activity 销毁之前立即调用。这可能发生在应用代码调用 finish() 时,或者系统由于配置变更需要销毁并重新创建 Activity 时。

配置变更导致 onDestroy() 被调用

屏幕旋转是一种配置变更,会导致 Activity 关闭并重新启动。要模拟此配置变更并检查其效果,请完成以下步骤:

  1. 编译并运行您的应用。
  2. 确保模拟器中的屏幕旋转锁定已禁用。
  3. 将设备或模拟器旋转到横向模式。您可以使用旋转按钮向左或向右旋转模拟器。
  4. 检查 Logcat,理解随着 Activity 关闭,它会按顺序调用 onPause()onStop()onDestroy()
2024-04-26 15:03:32.183  5716-5716  MainActivity            com.example.dessertclicker           D  onPause Called
2024-04-26 15:03:32.185  5716-5716  MainActivity            com.example.dessertclicker           D  onStop Called
2024-04-26 15:03:32.205  5716-5716  MainActivity            com.example.dessertclicker           D  onDestroy Called

设备旋转时的数据丢失

  1. 编译并运行您的应用,然后打开 Logcat。
  2. 点击几次纸杯蛋糕,注意卖出的甜点和总收入不为零。
  3. 确保模拟器中的屏幕旋转锁定已禁用。
  4. 将设备或模拟器旋转到横向模式。您可以使用旋转按钮向左或向右旋转模拟器。

11c9d83a11651608.png

  1. 检查 Logcat 中的输出。过滤 MainActivity 的输出。
2024-04-26 15:04:29.356  5809-5809  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 15:04:29.378  5809-5809  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 15:04:29.382  5809-5809  MainActivity            com.example.dessertclicker           D  onResume Called
2024-04-26 15:06:52.168  5809-5809  MainActivity            com.example.dessertclicker           D  onPause Called
2024-04-26 15:06:52.183  5809-5809  MainActivity            com.example.dessertclicker           D  onStop Called
2024-04-26 15:06:52.219  5809-5809  MainActivity            com.example.dessertclicker           D  onDestroy Called
2024-04-26 15:06:52.302  5809-5809  MainActivity            com.example.dessertclicker           D  onCreate Called
2024-04-26 15:06:52.308  5809-5809  MainActivity            com.example.dessertclicker           D  onStart Called
2024-04-26 15:06:52.312  5809-5809  MainActivity            com.example.dessertclicker           D  onResume Called

请注意,当设备或模拟器旋转屏幕时,系统会调用所有生命周期回调来关闭 Activity。然后,当 Activity 重新创建时,系统会调用所有生命周期回调来启动 Activity。

当设备旋转,Activity 关闭并重新创建时,Activity 会以默认值重新启动——甜点图片、卖出的甜点数量和总收入会重置为零。

要了解这些值为何被重置以及如何纠正它们,您需要了解可组合函数的生命周期以及它如何知道观察并保留其状态。

可组合函数的生命周期

您的应用 UI 最初是通过运行可组合函数在一个称为组合(Composition)的过程中构建的。

当您的应用状态发生变化时,会调度一次重新组合(Recomposition)。重新组合是指 Compose 重新执行状态可能已更改的可组合函数并创建更新的 UI。组合会更新以反映这些更改。

创建或更新组合的唯一方法是通过其初始组合和随后的重新组合。

可组合函数有自己的生命周期,独立于 Activity 生命周期。其生命周期由以下事件组成:进入组合、重新组合 0 次或多次,然后离开组合。

为了让 Compose 跟踪并触发重新组合,它需要知道何时状态发生了变化。要向 Compose 指示它应该跟踪对象的状态,该对象需要是 StateMutableState 类型。State 类型是不可变的,只能读取。MutableState 类型是可变的,允许读取和写入。

您在之前的 Codelab 中的Lemonade 应用Tip Time 应用中已经看到并使用过 MutableState

要创建可变变量 revenue,您可以使用 mutableStateOf 声明它。0 是其初始默认值。

var revenue = mutableStateOf(0)

虽然这足以让 Compose 在 revenue 值变化时触发重新组合,但不足以保留其更新后的值。每次可组合函数重新执行时,它都会将 revenue 值重新初始化为其初始默认值 0

要指示 Compose 在重新组合期间保留并重用其值,您需要使用 remember API 声明它。

var revenue by remember { mutableStateOf(0) }

如果 revenue 的值发生变化,Compose 会将所有读取此值的可组合函数安排重新组合。

虽然 Compose 在重新组合期间会记住 revenue 状态,但在配置变更期间不会保留此状态。要让 Compose 在配置变更期间保留状态,您必须使用 rememberSaveable

如需额外练习和信息,请参阅 Compose 中的状态简介 Codelab。

使用 rememberSaveable 在配置变更时保存值

您可以使用 rememberSaveable 函数来保存当 Android OS 销毁并重新创建 Activity 时您需要的值。

要在重新组合期间保存值,您需要使用 remember。要在重新组合和配置变更期间保存值,请使用 rememberSaveable

使用 rememberSaveable 保存值可确保在 Activity 恢复时(如果需要)该值可用。

  1. MainActivity 中,将当前使用 remember 的一组五个变量更新为 rememberSaveable
var revenue by remember { mutableStateOf(0) }
...
var currentDessertImageId by remember {
    mutableStateOf(desserts[currentDessertIndex].imageId)
}
var revenue by rememberSaveable { mutableStateOf(0) }
...
var currentDessertImageId by rememberSaveable {
    mutableStateOf(desserts[currentDessertIndex].imageId)
}
  1. 编译并运行您的应用。
  2. 点击几次纸杯蛋糕,注意卖出的甜点和总收入不为零。
  3. 将设备或模拟器旋转到横向模式。
  4. 观察到 Activity 销毁并重新创建后,甜点图片、卖出的甜点数量和总收入都恢复到了之前的值。

6. 解决方案代码

7. 总结

Activity 生命周期

  • Activity 生命周期是一组 Activity 转换所经历的状态。Activity 生命周期始于 Android OS 首次创建 Activity,止于 OS 销毁 Activity。
  • 当用户在 Activity 之间以及在应用内部和外部导航时,每个 Activity 都会在 Activity 生命周期的状态之间移动。
  • Activity 生命周期中的每个状态都有一个相应的回调方法,您可以在 Activity 类中重写这些方法。核心生命周期方法包括:onCreate()onRestart()onStart()onResume()onPause()onStop()onDestroy()
  • 要在 Activity 转换到某个生命周期状态时添加行为,请重写该状态对应的回调方法。
  • 要在 Android Studio 中为您的类添加骨架重写方法,请选择 Code > Override Methods... 或按下 Control+O

使用 Log 进行日志记录

  • Android 日志记录 API,特别是 Log 类,使您能够写入在 Android Studio 的 Logcat 中显示的短消息。
  • 使用 Log.d() 写入调试消息。此方法接受两个参数:日志标签(通常是类的名称)和日志消息(一个短字符串)。
  • 使用 Android Studio 中的 Logcat 窗口查看系统日志,包括您写入的消息。

配置变更

  • 当设备状态发生根本性变化时,会发生配置变更,系统解决此变更最简单的方式是销毁并重建 Activity。
  • 配置变更最常见的例子是用户将设备从纵向旋转到横向模式,或从横向旋转到纵向模式。配置变更也可能发生在设备语言改变或用户插入硬件键盘时。
  • 当发生配置变更时,Android 会调用所有 Activity 生命周期的关闭回调。然后,Android 会从头开始重新启动 Activity,运行所有生命周期启动回调。
  • 当 Android 由于配置变更关闭应用时,它会使用 onCreate() 重新启动 Activity。
  • 要保存需要在配置变更后保留的值,请使用 rememberSaveable 声明其变量。

了解更多