activity 生命周期

当用户浏览、退出和返回到您的应用时,您应用中的 Activity 实例会在其生命周期的不同状态间转换。Activity 类提供了许多回调 通知 activity 状态何时发生变化或 系统正在创建、停止、恢复 Activity 或销毁 activity 所在的进程

在生命周期回调方法中,您可以声明用户离开和再次进入 Activity 时 Activity 的行为方式。例如,如果你 构建流式视频播放器,您可以暂停视频并终止 网络连接。当用户回访时 您可以重新连接到网络并让用户从 同一位置。

每个回调都可让您执行特定工作, 与指定的状态变化相适应在合适的时间执行正确的作业,并妥善处理转换,这将提升应用的稳健性和性能。例如,良好的生命周期回调实现可以帮助应用 请避免以下行为:

  • 当用户在使用应用时接听来电,或切换至另一应用时崩溃。
  • 当用户未主动使用它时,消耗宝贵的系统资源。
  • 当用户离开应用并在稍后返回时,丢失用户的进度。
  • 当屏幕在横向和纵向之间旋转时,崩溃或丢失用户的进度。

本文档将详细介绍 Activity 生命周期。首先介绍生命周期范例。接下来,介绍每个回调: 执行期间内部发生的情况以及您需要实现的内容 。

然后,简要介绍 Activity 状态与导致进程被系统终止的漏洞之间的关系。最后,讨论了与 Google Analytics 数据之间的 activity 状态。

了解有关处理生命周期的信息,包括有关 最佳做法,请参见 使用生命周期感知型组件处理生命周期保存界面状态。 了解如何在 结合使用,请参阅 应用架构指南

Activity 生命周期概念

为了在 Activity 生命周期的各个阶段之间导航转换, Activity 类提供六个核心回调集: onCreate(), onStart(), onResume(), onPause(), onStop()onDestroy()。系统会调用 当 activity 进入新状态时,会同时触发每一个回调。

图 1 是对此范例的直观展现。

图 1. Activity 生命周期的简化图示。

当用户开始离开 Activity 时,系统会调用方法来销毁该 Activity。在某些情况下,活动只是其中的一部分 已分解且仍保留在内存中,例如当用户切换到 另一个应用。在这些情况下,activity 仍可返回前台。

如果用户返回该 activity, 从用户离开的位置继续播放除了少数例外情况,应用 受限来源 在后台运行时启动 activity 的应用

系统生成 终止给定进程及其中的 activity 取决于 。如需详细了解状态与 容易移除,请参阅有关 activity 状态和从内存中弹出的部分。

根据 Activity 的复杂程度,您可能不需要实现所有生命周期方法。但请务必注意 了解每种方法,并实现能够让应用行为相应功能的方法 满足用户预期

生命周期回调

本部分介绍 Activity 生命周期中所用回调方法的相关概念及实现信息。

有些操作属于 activity 生命周期方法。不过,您可以将代码 用于实现 组件,而不是 activity 生命周期方法。为此,您需要 以使依赖组件具有生命周期感知能力要了解如何 依赖组件生命周期感知型组件,请参见 使用生命周期感知型组件处理生命周期一文。

onCreate()

您必须实现此回调,它会在系统首次创建 Activity 时触发。Activity 会在创建后进入“已创建”状态。onCreate()中 方法,执行基本的应用启动逻辑, 在 activity 的整个生命周期内仅发生一次。

例如,您的 onCreate() 的实现可能会将数据绑定到列表,并将 activity 与 ViewModel, 并实例化一些类作用域变量。此方法会收到 参数 savedInstanceState,它是一个 Bundle 对象,该对象包含 activity 之前保存的状态。如果该 activity 具有 从未存在过,则 Bundle 对象的值为 null。

如果您有生命周期感知型组件,该组件关联到 活动时,它会接收 ON_CREATE 事件。系统会调用带有 @OnLifecycleEvent 注解的方法,以便具备生命周期感知能力 组件可以执行已创建状态所需的任何设置代码。

onCreate() 方法示例 显示 activity 的基本设置,例如声明界面 (在 XML 布局文件中定义)、定义成员变量并配置 部分界面在此示例中,XML 布局文件将 文件的资源 ID R.layout.main_activity 更改为 setContentView()

Kotlin

lateinit var textView: TextView

// Some transient state for the activity instance.
var gameState: String? = null

override fun onCreate(savedInstanceState: Bundle?) {
    // Call the superclass onCreate to complete the creation of
    // the activity, like the view hierarchy.
    super.onCreate(savedInstanceState)

    // Recover the instance state.
    gameState = savedInstanceState?.getString(GAME_STATE_KEY)

    // Set the user interface layout for this activity.
    // The layout is defined in the project res/layout/main_activity.xml file.
    setContentView(R.layout.main_activity)

    // Initialize member TextView so it is available later.
    textView = findViewById(R.id.text_view)
}

// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    textView.text = savedInstanceState?.getString(TEXT_VIEW_KEY)
}

// Invoked when the activity might be temporarily destroyed; save the instance state here.
override fun onSaveInstanceState(outState: Bundle?) {
    outState?.run {
        putString(GAME_STATE_KEY, gameState)
        putString(TEXT_VIEW_KEY, textView.text.toString())
    }
    // Call superclass to save any view hierarchy.
    super.onSaveInstanceState(outState)
}

Java

TextView textView;

// Some transient state for the activity instance.
String gameState;

@Override
public void onCreate(Bundle savedInstanceState) {
    // Call the superclass onCreate to complete the creation of
    // the activity, like the view hierarchy.
    super.onCreate(savedInstanceState);

    // Recover the instance state.
    if (savedInstanceState != null) {
        gameState = savedInstanceState.getString(GAME_STATE_KEY);
    }

    // Set the user interface layout for this activity.
    // The layout is defined in the project res/layout/main_activity.xml file.
    setContentView(R.layout.main_activity);

    // Initialize member TextView so it is available later.
    textView = (TextView) findViewById(R.id.text_view);
}

// This callback is called only when there is a saved instance previously saved using
// onSaveInstanceState(). Some state is restored in onCreate(). Other state can optionally
// be restored here, possibly usable after onStart() has completed.
// The savedInstanceState Bundle is same as the one used in onCreate().
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    textView.setText(savedInstanceState.getString(TEXT_VIEW_KEY));
}

// Invoked when the activity might be temporarily destroyed; save the instance state here.
@Override
public void onSaveInstanceState(Bundle outState) {
    outState.putString(GAME_STATE_KEY, gameState);
    outState.putString(TEXT_VIEW_KEY, textView.getText());

    // Call superclass to save any view hierarchy.
    super.onSaveInstanceState(outState);
}

除了定义 XML 文件并将其传递给 setContentView() 之外, 可以在您的 activity 代码中创建新的 View 对象,并构建 将新的 View 对象插入 ViewGroup。然后,使用该布局,方法是传递 根 ViewGroupsetContentView()。 如需详细了解如何创建界面,请参阅 界面文档。

您的活动不会保留在“已创建”的 状态。onCreate() 方法完成执行后,activity 会进入 Started 状态,系统会调用 onStart()onResume() 方法 连续调用。

onStart()

当 Activity 进入“已启动”状态时,系统会 会调用 onStart()。 此调用会以 应用准备 activity 进入前台并变为可互动状态。 例如,使用以下方法 界面已初始化。

当 activity 进入“已启动”状态时,所有具有生命周期感知能力的组件 activity 生命周期的剩余时间会收到 ON_START 事件。

onStart() 方法完成 与“已创建”状态一样,activity 不会保持 “已启动”状态此回调完成后,Activity 将进入 处于已恢复状态,并且系统会调用 onResume() 方法。

onResume()

当 activity 进入“已恢复”状态时,会进入前台,并且 系统调用 onResume() 回调。这是应用与用户互动的状态。应用会一直保持这种状态,直到 使焦点远离应用,例如接听来电的设备、用户 导航到其他 activity,或设备屏幕关闭。

当 activity 进入“已恢复”状态时,所有具有生命周期感知能力的组件都会绑定, activity 生命周期的剩余时间会收到 ON_RESUME 事件。这时,生命周期组件可以启用在组件可见且位于前台时需要运行的任何功能,例如启动相机预览。

当发生中断事件时,活动会进入已暂停状态 并且系统会调用 onPause() 回调。

如果 Activity 返回到 从“已暂停”状态转换为“已恢复”状态,系统会再次调用 onResume() 方法结合使用。因此,请实施 onResume(),用于初始化您在发布期间释放的组件 onPause(),以及执行任何其他 每次活动进入“已恢复”状态时都必须进行的初始化 状态。

下面是一个生命周期感知型组件示例,该组件会在发生以下情况时访问相机: 组件收到 ON_RESUME 事件:

Kotlin

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    fun initializeCamera() {
        if (camera == null) {
            getCamera()
        }
    }
    ...
}

Java

public class CameraComponent implements LifecycleObserver {

    ...

    @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
    public void initializeCamera() {
        if (camera == null) {
            getCamera();
        }
    }
    ...
}

完成上述操作后, LifecycleObserver 收到 ON_RESUME 事件。不过,在多窗口模式下 即使处于“已暂停”状态,广告素材也完全可见例如,当 应用处于多窗口模式,并且用户点按了 包含您的 activity,则您的 activity 将进入“已暂停”状态。

如果您 希望相机仅在应用恢复运行时(可见) 并在前台运行),然后初始化镜头, ON_RESUME 个事件 如上文所述。如果您想在活动期间让摄像头保持活动状态 已暂停但可见(例如在多窗口模式下),那么 在 ON_START 事件后初始化相机。

但是,如果使用相机 当 activity 处于“已暂停”状态时,另一个 activity 可能会拒绝使用摄像头 在多窗口模式下恢复了应用。有时,为确保 虽然相机在 activity 处于“已暂停”状态时仍处于活动状态,但实际上可能会降低 提升整体用户体验

因此,请仔细考虑 因此,在生命周期中控制共享系统资源是最合适的选择, 多窗口模式的上下文。详细了解如何支持多窗口模式 请参阅多窗口支持

无论您选择在哪个构建事件中执行初始化操作,都请务必使用相应的生命周期事件来释放资源。如果 ON_START 事件后, ON_STOP 事件。如果您 在 ON_RESUME 事件后初始化,在 ON_PAUSE 事件。

上述代码段会将相机初始化代码放置在 生命周期感知型组件您也可以直接将此代码放入 activity 生命周期回调,例如 onStart()onStop(),但我们不建议这样做。添加此逻辑 独立的生命周期感知型组件,让您可以重复使用该组件 而无需复制代码。如需了解如何创建生命周期感知型组件,请参阅 使用生命周期感知型组件处理生命周期

onPause()

系统会将此方法作为用户离开的第一个 但这并不总是意味着 activity 会被销毁。 它表明 activity 不再位于前台,但它处于 在用户处于多窗口模式时仍然可见。 有几种原因可能会导致 activity 进入 此状态:

  • 中断应用执行的事件,如“ onResume() 回调会暂停当前 Activity。这是最常见的情况。
  • 在多窗口模式下,只有一个应用获得焦点 而系统会暂停所有其他应用。
  • 打开新的半透明 activity(例如对话框) 会暂停其涵盖的活动。只要 该 activity 部分可见但未获得焦点, 保持暂停状态。

当 activity 进入“已暂停”状态时,所有具有生命周期感知能力的组件 activity 生命周期的剩余时间会收到 ON_PAUSE 事件。这时,生命周期组件可以停止在组件未位于前台时无需运行的任何功能,例如停止相机预览。

使用 onPause() 方法暂停或 调整无法继续或可能继续适度的操作, Activity处于“已暂停”状态时, 预计很快就会恢复。

您还可以使用 onPause() 方法 释放系统资源、传感器(如 GPS)的句柄,或任何 影响电池续航时间 需要它们。

不过,正如在有关 onResume() 的部分中所述,已暂停的 如果应用处于多窗口模式,activity 可能仍然完全可见。 不妨考虑使用 onStop()(而非 onPause())来全面发布或调整 与界面相关的资源和操作,有助于更好地支持多窗口模式。

以下是一个 LifecycleObserver 示例。 对 ON_PAUSE 事件的响应相当于上述事件 ON_RESUME 事件示例,在上述时间过后释放初始化的相机 收到 ON_RESUME 事件:

Kotlin

class CameraComponent : LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    fun releaseCamera() {
        camera?.release()
        camera = null
    }
    ...
}

Java

public class JavaCameraComponent implements LifecycleObserver {
    ...
    @OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
    public void releaseCamera() {
        if (camera != null) {
            camera.release();
            camera = null;
        }
    }
    ...
}

本示例将相机释放代码置于 LifecycleObserver 收到 ON_PAUSE 事件。

onPause() 的执行时间非常短, 不一定有足够的时间来执行保存操作。为此 使用 onPause() 来保存应用或用户 数据、进行网络调用或执行数据库事务。此类工作 在方法完成之前完成。

相反,在 onStop()。更多信息 可在 Kubernetes 中 onStop(),请参阅下一部分。如需详细了解如何将 请参阅保存和恢复状态部分。

onPause() 方法的完成并不意味着 Activity 离开“已暂停”状态。相反,activity: 会保持这种状态,直到 activity 恢复或完全变为 对用户不可见如果 Activity 恢复,系统将再次调用 onResume() 回调。

如果 从“已暂停”状态返回到“已恢复”状态, 驻留在内存中的 Activity 实例,在召回 该实例可在系统调用 onResume() 时使用。 在这种情况下,您不需要重新初始化在执行任何 回调方法,这些回调方法可恢复“已恢复”状态。如果 activity 变为 系统会调用 onStop()

onStop()

当您的 activity 不再对用户可见时,它会进入 已停止状态,系统将调用 onStop() 回调。当新启动的 activity 覆盖整个屏幕时,可能会发生这种情况。通过 系统还会调用 onStop() 当 activity 完成运行并即将终止时。

当 activity 进入“已停止”状态时,所有生命周期感知型组件都将与 activity 生命周期的剩余时间会收到 ON_STOP 事件。这时,生命周期组件可以停止在组件未显示在屏幕上时无需运行的任何功能。

onStop() 方法中,释放或调整 应用对用户不可见时不需要的资源。例如,应用可以暂停动画效果,或从精确位置更新切换到粗略位置更新。使用 onStop()(原价 onPause()) 意味着即使用户在多窗口模式下查看您的 activity,与界面相关的工作仍会继续 模式。

此外,使用 onStop() 执行 CPU 相对密集的关闭操作。例如,如果 将信息保存到数据库是最好的时机, 您可能会在onStop()期间执行此操作。以下示例展示了 onStop() 的实现,它将草稿笔记内容保存到持久性存储空间中:

Kotlin

override fun onStop() {
    // Call the superclass method first.
    super.onStop()

    // Save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    val values = ContentValues().apply {
        put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText())
        put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle())
    }

    // Do this update in background on an AsyncQueryHandler or equivalent.
    asyncQueryHandler.startUpdate(
            token,     // int token to correlate calls
            null,      // cookie, not used here
            uri,       // The URI for the note to update.
            values,    // The map of column names and new values to apply to them.
            null,      // No SELECT criteria are used.
            null       // No WHERE columns are used.
    )
}

Java

@Override
protected void onStop() {
    // Call the superclass method first.
    super.onStop();

    // Save the note's current draft, because the activity is stopping
    // and we want to be sure the current note progress isn't lost.
    ContentValues values = new ContentValues();
    values.put(NotePad.Notes.COLUMN_NAME_NOTE, getCurrentNoteText());
    values.put(NotePad.Notes.COLUMN_NAME_TITLE, getCurrentNoteTitle());

    // Do this update in background on an AsyncQueryHandler or equivalent.
    asyncQueryHandler.startUpdate (
            mToken,  // int token to correlate calls
            null,    // cookie, not used here
            uri,    // The URI for the note to update.
            values,  // The map of column names and new values to apply to them.
            null,    // No SELECT criteria are used.
            null     // No WHERE columns are used.
    );
}

上述代码示例直接使用 SQLite。不过,我们建议您使用 Room 用于在 SQLite 上提供抽象层的持久性库。学习内容 使用 Room 的好处以及如何在应用中实现 Room, 请参阅 Room 持久性库 指南。

当您的 activity 进入“已停止”状态时,Activity 对象会驻留在内存中:它维护着所有状态和成员, 信息,但不会附加到窗口管理器。当活动 恢复时都会调用这些信息

您无需 重新初始化在任何回调方法期间创建的组件 才能进入“已恢复”状态该系统还会跟踪当前的 每个 View 对象的状态,因此如果 用户在 EditText widget 中输入文本, 则会保留这些内容,因此您无需进行保存和恢复。

注意:Activity 停止后,如果系统需要恢复内存,可能会销毁包含该 Activity 的进程。即使系统在 activity 期间销毁该进程, 停止后,系统仍会保留 View 的状态 对象,例如 EditText widget 中的文本, Bundle - 键值对的 blob,并恢复它们 返回该 activity。对于 如需详细了解如何恢复用户返回的 Activity,请参阅 保存和恢复状态部分。

进入“已停止”状态后,Activity 要么返回与用户互动,要么结束运行并消失。如果 Activity 返回,系统将调用 onRestart()。如果 Activity 完成运行,系统会调用 onDestroy()

onDestroy()

销毁 Ativity 之前,系统会先调用 onDestroy()。系统调用此回调的原因有两种:

  1. 由于用户完全关闭了 activity,因此 activity 正在结束 或由于 finish()正在 调用该方法。
  2. 由于配置,系统暂时销毁 activity 更改,例如设备旋转或进入多窗口模式。

当 activity 进入已销毁状态时,所有具有生命周期感知能力的组件都会绑定, activity 生命周期的剩余时间会收到 ON_DESTROY 事件。这就是 生命周期组件可以清理 Activity 会被销毁。

您不必在 Activity 中添加逻辑来确定其被销毁的原因, 使用 ViewModel 对象来包含 Activity的相关查看数据。如果重新创建了 Activity 由于配置变更,ViewModel 无需执行任何操作, 它会保留下来并提供给下一个 Activity 实例。

如果未重新创建 Activity,则 ViewModel 调用了 onCleared() 方法,其中 它可以在销毁之前清理所需的任何数据您可以通过 isFinishing() 方法。

如果 activity 正在结束,则 onDestroy() 是最后一个生命周期回调 activity 接收的任何数据。如果因配置而调用 onDestroy() 系统会立即创建新的 activity 实例,然后调用 <ph type="x-smartling-placeholder"></ph> onCreate() 新实例。

onDestroy() 回调将释放之前未释放的所有资源 回调,例如 onStop()

Activity 状态和从内存中弹出

系统会在需要释放 RAM 时终止进程。系统概率的 终止给定进程取决于当时进程的状态。反之,进程状态取决于在进程中运行的 Activity 的状态。表 1 显示了进程状态、活动之间的相关性 状态以及系统终止进程的可能性此表仅在进程未运行其他类型的 应用组件。

系统终止进程的可能性 进程状态 最终 activity 状态
最低 前台(拥有或即将获得焦点) 已恢复
可见(无焦点) 已开始/已暂停
较高 背景(不可见) 已停止
最高 未连接 已销毁

表 1. 进程生命周期与 activity 状态之间的关系。

系统永远不会直接终止 Activity 以释放内存,相反, 终止 activity 在其中运行的进程,不仅销毁 activity 还要运行该进程中的所有其他任务了解如何保留 并在系统发起的进程终止时恢复 activity 的界面状态 请参阅保存和恢复状态部分。

用户还可以使用“应用程序管理器”中的“设置” 以终止相应的应用。

如需详细了解进程,请参阅 进程和线程 概览

保存和恢复瞬时界面状态

用户期望 Activity 的界面状态在整个配置变更(例如旋转或切换到多窗口模式)期间保持不变。不过,在这种配置下,默认情况下系统会销毁 activity 更改发生时,清除存储在 activity 实例中的任何界面状态。

同样,如果用户暂时从您的应用切换到其他应用,并在稍后返回您的应用,他们也希望界面状态保持不变。但是,在发生故障时,系统可能会销毁您应用的进程。 用户离开,且您的 activity 已停止。

当系统约束条件销毁 activity 时,保留 通过结合使用 ViewModel onSaveInstanceState()、 和/或本地存储详细了解用户期望与系统对比 行为以及如何以最佳方式保留复杂的界面状态数据, 系统发起的活动和进程终止,请参见 保存界面状态

本部分概述了什么是实例状态以及如何实现 onSaveInstance() 方法,这是对 activity 本身的回调。如果您的 界面数据是轻量级数据,您可以单独使用 onSaveInstance() 来保留界面 状态。 但由于 onSaveInstance() 会产生序列化/反序列化费用, 在大多数情况下,您同时使用 ViewModelonSaveInstance(),因为 保存界面状态

注意 :如需详细了解配置更改,请参阅如何限制 Activity 以及如何从 请查看系统和 Jetpack Compose,请参阅 处理配置更改页面。

实例状态

在以下几种情况下,您的 activity 会因正常应用而被销毁 行为,例如当用户按返回按钮或您的 activity 时 通过调用 finish() 方法。

当您的 activity 因用户按“返回”而销毁时 或者 activity 自行结束,系统和用户的概念 Activity 实例已永久删除。在这些 用户的期望与系统的行为相符,并且您不会 需要完成任何额外的工作

但是,如果系统因系统限制(例如 配置更改或内存压力),虽然实际 Activity 实例都不复存在,系统会记住它曾经存在过。如果用户尝试回退到该 Activity,系统将使用一组描述 Activity 销毁时状态的已保存数据新建该 Activity 的实例。

系统用于恢复 称为实例状态。它是一个 键值对存储在 Bundle 对象中。默认情况下, 系统使用 Bundle 实例状态来保存信息 关于 activity 布局中的每个 View 对象,例如 向 EditText widget。

这样,如果您的 Activity 实例被销毁并重新创建,布局状态便会恢复为其先前的状态,且您无需编写代码。但是,您的 Activity 可能包含您要恢复的更多状态信息,例如追踪用户在 Activity 中的进程的成员变量。

注意:为了使 Android 系统恢复 Activity 中视图的状态,每个视图必须具有 android:id 属性提供的唯一 ID。

一个 Bundle 对象不适合保留超过 数据量很少,因为它需要在主线程上进行序列化, 系统进程内存如果只想保留少量数据 采用多种方法来保留数据,使用永久性本地存储 onSaveInstanceState() 方法和 ViewModel 类,如 中所述 保存界面状态

使用 onSaveInstanceState() 保存简单轻量的界面状态

当您的 Activity 开始停止时,系统会调用 onSaveInstanceState() 方法,以便您的 Activity 可以将状态信息保存到实例状态 Bundle 中。此方法的默认实现保存有关 Activity 视图层次结构状态的瞬时信息,例如 EditText 微件中的文本或 ListView 微件的滚动位置。

如需为您的 activity 保存其他实例状态信息,请替换 onSaveInstanceState() 并将键值对添加到保存的 Bundle 对象 以防 activity 意外销毁。如果您替换 onSaveInstanceState() 时,您需要调用父类实现 如果您希望默认实现保存视图层次结构的状态,可以使用此属性。 具体可见以下示例:

Kotlin

override fun onSaveInstanceState(outState: Bundle?) {
    // Save the user's current game state.
    outState?.run {
        putInt(STATE_SCORE, currentScore)
        putInt(STATE_LEVEL, currentLevel)
    }

    // Always call the superclass so it can save the view hierarchy state.
    super.onSaveInstanceState(outState)
}

companion object {
    val STATE_SCORE = "playerScore"
    val STATE_LEVEL = "playerLevel"
}

Java

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...


@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state.
    savedInstanceState.putInt(STATE_SCORE, currentScore);
    savedInstanceState.putInt(STATE_LEVEL, currentLevel);

    // Always call the superclass so it can save the view hierarchy state.
    super.onSaveInstanceState(savedInstanceState);
}

注意: onSaveInstanceState()”不是 在用户显式关闭 activity 时调用,或者在其他情况下, 调用 finish()

如需保存持久性数据(例如用户偏好设置或数据库的数据), 在 activity 位于前台时抓住适当的机会。 如果没有这样的机会,请在数据迁移期间 onStop() 方法。

使用保存的实例状态恢复 Activity 界面状态

重建先前被销毁的 Activity 后,您可以从系统传递给 Activity 的 Bundle 中恢复保存的实例状态。 onCreate() onRestoreInstanceState() 回调方法会收到相同的 Bundle,其中包含 实例状态信息。

由于 onCreate() 方法 调用系统是否正在创建新的 activity 实例 或者重新创建上一个事件,您需要检查状态 Bundle 为 null。如果为 null,系统将新建 Activity 实例,而不会恢复之前销毁的实例。

以下代码段展示了如何恢复一些 onCreate() 中的状态数据:

Kotlin

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState) // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance.
    if (savedInstanceState != null) {
        with(savedInstanceState) {
            // Restore value of members from saved state.
            currentScore = getInt(STATE_SCORE)
            currentLevel = getInt(STATE_LEVEL)
        }
    } else {
        // Probably initialize members with default values for a new instance.
    }
    // ...
}

Java

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // Always call the superclass first

    // Check whether we're recreating a previously destroyed instance.
    if (savedInstanceState != null) {
        // Restore value of members from saved state.
        currentScore = savedInstanceState.getInt(STATE_SCORE);
        currentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // Probably initialize members with default values for a new instance.
    }
    // ...
}

不要在 Cloud Shell 中 onCreate(),您可以选择实现 onRestoreInstanceState(),系统会在 onStart() 方法。系统会调用 onRestoreInstanceState() 仅当存在要恢复的已保存状态时 无需检查 Bundle 是否为 null。

Kotlin

override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
    // Always call the superclass so it can restore the view hierarchy.
    super.onRestoreInstanceState(savedInstanceState)

    // Restore state members from saved instance.
    savedInstanceState?.run {
        currentScore = getInt(STATE_SCORE)
        currentLevel = getInt(STATE_LEVEL)
    }
}

Java

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy.
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance.
    currentScore = savedInstanceState.getInt(STATE_SCORE);
    currentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

注意:请始终调用 onRestoreInstanceState() 以便默认实现可以恢复视图层次结构的状态。

在 Activity 之间导航

在 Activity 的整个运行过程中,应用可能会多次进入和退出 Activity 应用的生命周期,例如当用户点按设备的“返回”按钮时 或者该 activity 会启动其他 activity。

本部分介绍了实现成功的 Activity 转换需要了解的主题。这些主题包括从另一个 Activity 启动 Activity、保存 Activity 状态,以及恢复 Activity 状态。

从一个 Activity 启动另一个 Activity

Activity 通常需要在某个时刻启动另一个 Activity。例如,当应用需要从当前屏幕移动到新屏幕时,就会出现这种需求。

取决于您的 activity 是否需要从新 activity 返回结果 使用 startActivity() 方法或 startActivityForResult() 方法。这两种方法都需要传入一个 Intent 对象。

Intent 对象会指定确切的 或说明您想要执行的操作类型。 系统会为您选择合适的 activity,可以是 从另一个应用复制而来。Intent 对象还可以携带由已启动的 Activity 使用的少量数据。如需详细了解 Intent 类,请参阅 Intent 和 Intent 过滤器

startActivity()

如果新启动的 Activity 不需要返回结果,当前 Activity 可以通过调用 startActivity() 方法来启动它。

在自己的应用中工作时,您通常只需启动已知 Activity。例如,以下代码段显示如何启动一个名为 SignInActivity 的 Activity。

Kotlin

val intent = Intent(this, SignInActivity::class.java)
startActivity(intent)

Java

Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

您的应用可能还希望使用 Activity 中的数据执行某些操作,例如发送电子邮件、短信或状态更新。在这种情况下,您的应用自身可能不具有执行此类操作所需的 activity, 因此您可以改为利用设备上其他应用提供的 activity 即可为您执行相应操作

这就是 intent 的真正价值所在。您可以创建一个 intent,系统会启动相应的 其他应用中的活动如果有多个 Activity 可以处理 intent,用户可以选择要使用哪一个。例如,如果您希望用户 您可以创建以下 intent:

Kotlin

val intent = Intent(Intent.ACTION_SEND).apply {
    putExtra(Intent.EXTRA_EMAIL, recipientArray)
}
startActivity(intent)

Java

Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

添加到 intent 的 EXTRA_EMAIL extra 是一个字符串数组, 电子邮件地址。当电子邮件应用 响应此 intent,它会读取 extra 中提供的字符串数组,并 会将地址放置在“to”中字段。在本课中, 电子邮件应用的 activity 会启动,当用户完成时, activity 会继续运行。

startActivityForResult()

有时,您会希望在 Activity 结束时从 Activity 中获取返回结果。例如,您可以开始 一个 activity,可让用户在联系人列表中选择一个人。当它结束时,它会返回 所选对象。为此,您需要调用 startActivityForResult(Intent, int) 方法,其中 整数参数用于标识相应调用。

此标识符用于区分对 startActivityForResult(Intent, int) 。它不是全局标识符 并且不会与其他应用或 activity 发生冲突。系统会通过您的 onActivityResult(int, int, Intent) 方法。

当子级 Activity 退出时,它可以调用 setResult(int) 将数据返回到其父级。子 activity 必须提供结果代码,该代码可以是标准结果 RESULT_CANCELEDRESULT_OK 或任何自定义值 起价:RESULT_FIRST_USER

此外, 子 activity 可以选择性地返回 Intent 对象包含所需的任何其他数据。父 activity 使用 onActivityResult(int, int, Intent) 方法,以及父 activity 原本的整数标识符, 以接收信息。

如果子级 Activity 由于任何原因(例如崩溃)而失败,父级 Activity 将收到代码为 RESULT_CANCELED 的结果。

Kotlin

class MyActivity : Activity() {
    // ...

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
            // When the user center presses, let them pick a contact.
            startActivityForResult(
                    Intent(Intent.ACTION_PICK,Uri.parse("content://contacts")),
                    PICK_CONTACT_REQUEST)
            return true
        }
        return false
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
        when (requestCode) {
            PICK_CONTACT_REQUEST ->
                if (resultCode == RESULT_OK) {
                    // A contact was picked. Display it to the user.
                    startActivity(Intent(Intent.ACTION_VIEW, intent?.data))
                }
        }
    }

    companion object {
        internal val PICK_CONTACT_REQUEST = 0
    }
}

Java

public class MyActivity extends Activity {
     // ...

     static final int PICK_CONTACT_REQUEST = 0;

     public boolean onKeyDown(int keyCode, KeyEvent event) {
         if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
             // When the user center presses, let them pick a contact.
             startActivityForResult(
                 new Intent(Intent.ACTION_PICK,
                 new Uri("content://contacts")),
                 PICK_CONTACT_REQUEST);
            return true;
         }
         return false;
     }

     protected void onActivityResult(int requestCode, int resultCode,
             Intent data) {
         if (requestCode == PICK_CONTACT_REQUEST) {
             if (resultCode == RESULT_OK) {
                 // A contact was picked. Display it to the user.
                 startActivity(new Intent(Intent.ACTION_VIEW, data));
             }
         }
     }
 }

协调 Activity

当一个 Activity 启动另一个 Activity 时,它们都会经历生命周期转换。第一个 Activity 停止运行并进入“已暂停”或“已停止”状态,同时创建另一个 Activity。如果这些 Activity 共享保存到磁盘或其他位置的数据,必须要明确第一个 Activity 在创建第二个 Activity 之前并未完全停止。相反,启动第二个 Activity 的过程与停止第一个 Activity 的过程重叠。

生命周期回调的顺序已明确定义,尤其是在两个 activity 同时 同一个进程(也就是同一个应用),其中一个会启动另一个。以下是 Activity A 启动 Activity B 时的操作发生顺序:

  1. Activity A 的 onPause() 方法执行。
  2. Activity B 的 onCreate()onStart()onResume() 方法依次执行activity B 现在具有用户焦点。
  3. 如果 activity A 在屏幕上不再可见,系统会执行其 onStop() 方法。

利用这种生命周期回调序列,您可以管理 将信息从一个活动传递到另一个活动