android代理生命周期,了解 Activity 生命周期

当用户浏览、退出和返回到您的应用时,您应用中的

在生命周期回调方法中,您可以声明用户离开和再次进入 Activity 时 Activity 的行为方式。例如,如果您正构建流媒体视频播放器,当用户切换至另一应用时,您可能要暂停视频或终止网络连接。当用户返回时,您可以重新连接网络并允许用户从同一位置继续播放视频。换言之,每个回调都支持您执行适合给定状态变更的特定作业。在合适的时间执行正确的作业,并妥善处理转换,这将提升应用的稳健性和性能。例如,良好的生命周期回调实现有助于防止应用出现以下问题:

当用户在使用应用时接听来电,或切换至另一应用时崩溃。

当用户未主动使用它时,消耗宝贵的系统资源。

当用户离开应用并在稍后返回时,丢失用户的进度。

当屏幕在横向和纵向之间旋转时,崩溃或丢失用户的进度。

本文档将详细介绍 Activity 生命周期。首先介绍生命周期范例。接着介绍每个回调:它们执行时内部发生了什么,以及您应该在执行期间实现什么。然后,简要介绍 Activity 状态与导致进程被系统终止的漏洞之间的关系。最后,讨论与在 Activity 状态之间转换相关的若干主题。

如需了解有关处理生命周期的信息(包括最佳做法的相关指导),请参阅使用生命周期感知型组件处理生命周期和保存界面状态。如需了解如何将 Activity 与架构组件结合使用,以构建生产质量的稳健应用,请参阅应用架构指南。

Activity 生命周期概念

为了在 Activity 生命周期的各个阶段之间导航转换,Activity 类提供六个核心回调:

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

a6ca95870a0e62adce660f864ea6bb17.png

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

当用户开始离开 Activity 时,系统会调用方法来销毁该 Activity。在某些情况下,此销毁只是部分销毁;Activity 仍然驻留在内存中(例如当用户切换至另一应用时),并且仍然可以返回到前台。如果用户返回到该 Activity,Activity 会从用户离开时的位置继续运行。除了少数例外,应用在后台运行时会受到限制,无法启动 Activity。

系统终止给定进程及其中 Activity 的可能性取决于当时 Activity 的状态。Activity 状态和从内存中弹出 会更详细地介绍状态与弹出漏洞之间的关系。

根据 Activity 的复杂程度,您可能不需要实现所有生命周期方法。但是,请务必了解每个方法,并实现能够确保应用按用户预期方式运行的方法,这非常重要。

在下一部分中,本文档将详细介绍用于处理状态间转换的回调。

生命周期回调

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

某些操作(例如调用 setContentView())属于 Activity 生命周期方法本身。不过,用于实现依赖组件操作的代码应放在组件本身内。为此,您必须使依赖组件具有生命周期感知能力。请参阅使用生命周期感知型组件处理生命周期,了解如何让您的依赖组件获得生命周期感知能力。

onCreate()

您必须实现此回调,它会在系统首次创建 Activity 时触发。Activity 会在创建后进入“已创建”状态。在 onCreate() 的实现可能会将数据绑定到列表,将 Activity 与 ViewModel 相关联,并实例化某些类作用域变量。此方法会接收 savedInstanceState 参数,后者是包含 Activity 先前保存状态的

如果您有一个生命周期感知型组件与您的 Activity 生命周期相关联,该组件将收到 ON_CREATE 事件。系统将调用带有 @OnLifecycleEvent 注释的方法,以使您的生命周期感知型组件可以执行已创建状态所需的任何设置代码。

R.layout.main_activity 传递给

Kotlin

lateinit var textView: TextView

// some transient state for the activity instance

var gameState: String? = null

override fun onCreate(savedInstanceState: Bundle?) {

// call the super class onCreate to complete the creation of activity like

// the view hierarchy

super.onCreate(savedInstanceState)

// recovering the instance state

gameState = savedInstanceState?.getString(GAME_STATE_KEY)

// set the user interface layout for this activity

// the layout file is defined in the project res/layout/main_activity.xml file

setContentView(R.layout.main_activity)

// initialize member TextView so we can manipulate it later

textView = findViewById(R.id.text_view)

}

// This callback is called only when there is a saved instance that is previously saved by using

// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore

// other state 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 may 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 super class onCreate to complete the creation of activity like

// the view hierarchy

super.onCreate(savedInstanceState);

// recovering the instance state

if (savedInstanceState != null) {

gameState = savedInstanceState.getString(GAME_STATE_KEY);

}

// set the user interface layout for this activity

// the layout file is defined in the project res/layout/main_activity.xml file

setContentView(R.layout.main_activity);

// initialize member TextView so we can manipulate it later

textView = (TextView) findViewById(R.id.text_view);

}

// This callback is called only when there is a saved instance that is previously saved by using

// onSaveInstanceState(). We restore some state in onCreate(), while we can optionally restore

// other state 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 may 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 文件,然后将其传递给 界面文档。

您的 Activity 并未处于“已创建”状态。下一部分将介绍

onStart()

当 Activity 进入“已开始”状态时,系统会调用此回调。

当 Activity 进入已开始状态时,与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_START 事件。

onResume()

Activity 会在进入“已恢复”状态时来到前台,然后系统调用

当 Activity 进入已恢复状态时,与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_RESUME 事件。这时,生命周期组件可以启用在组件可见且位于前台时需要运行的任何功能,例如启动相机预览。

当发生中断事件时,Activity 进入“已暂停”状态,系统调用

如果 Activity 从“已暂停”状态返回“已恢复”状态,系统将再次调用 onPause() 期间释放的组件,并执行每次 Activity 进入“已恢复”状态时必须完成的任何其他初始化操作。

以下是生命周期感知型组件的示例,该组件在收到 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 的窗口时,您的 Activity 将进入“已暂停”状态。如果您希望相机仅在应用处于“已恢复”(可见且在前台运行)状态时可用,请在收到上述 ON_RESUME 事件后初始化相机。如果您希望在 Activity 处于“已暂停”状态但可见时(例如在多窗口模式下)保持相机可用,应在收到 ON_START 事件后初始化相机。但请注意,若要让相机在 Activity 处于“已暂停”状态时可用,可能会导致系统在多窗口模式下拒绝其他处于“已恢复”状态的应用访问相机。有时可能有必要让相机在 Activity 处于“已暂停”状态时保持可用,但这样做实际可能会降低整体用户体验。请仔细考虑,生命周期的哪个阶段更适合在多窗口环境下控制共享系统资源。如需详细了解如何支持多窗口模式,请参阅多窗口支持。

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

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

onPause()

系统将此方法视为用户将要离开您的 Activity 的第一个标志(尽管这并不总是意味着 Activity 会被销毁);此方法表示 Activity 不再位于前台(尽管在用户处于多窗口模式时 Activity 仍然可见)。使用 onPause() 方法暂停或调整当 Activity 处于“已暂停”状态时不应继续(或应有节制地继续)的操作,以及您希望很快恢复的操作。Activity 进入此状态的原因有很多。例如:

如 onResume() 部分所述,某个事件会中断应用执行。这是最常见的情况。

在 Android 7.0(API 级别 24)或更高版本中,有多个应用在多窗口模式下运行。无论何时,都只有一个应用(窗口)可以拥有焦点,因此系统会暂停所有其他应用。

有新的半透明 Activity(例如对话框)处于开启状态。只要 Activity 仍然部分可见但并未处于焦点之中,它便会一直暂停。

当 Activity 进入已暂停状态时,与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_PAUSE 事件。这时,生命周期组件可以停止在组件未位于前台时无需运行的任何功能,例如停止相机预览。

您还可以使用 onPause() 方法释放系统资源、传感器(例如 GPS)手柄,或当您的 Activity 暂停且用户不需要它们时仍然可能影响电池续航时间的任何资源。然而,正如上文的 onResume() 部分所述,如果处于多窗口模式,“已暂停”的 Activity 仍完全可见。因此,您应该考虑使用 onStop() 而非 onPause() 来完全释放或调整与界面相关的资源和操作,以便更好地支持多窗口模式。

响应 ON_PAUSE 事件的以下 LifecycleObserver 示例与上述 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 事件后放置相机释放代码。如前所述,请参阅使用生命周期感知型组件处理生命周期了解如何创建生命周期感知型组件。

不应使用 onStop()。如需详细了解如何保存数据,请参阅保存和恢复 Activity 状态。

onStop()

如果您的 Activity 不再对用户可见,说明其已进入“已停止”状态,因此系统将调用 例如,当新启动的 Activity 覆盖整个屏幕时,可能会发生这种情况。如果 Activity 已结束运行并即将终止,系统还可以调用

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

您还应使用

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 停止后,如果系统需要恢复内存,可能会销毁包含该 Activity 的进程。即使系统在 Activity 停止后销毁相应进程,系统仍会保留 保存和恢复 Activity 状态。

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

onDestroy()

销毁 Ativity 之前,系统会先调用 onDestroy()。系统调用此回调的原因如下:Activity 即将结束(由于用户彻底关闭 Activity 或由于系统为 Activity 调用 finish()),或者

由于配置变更(例如设备旋转或多窗口模式),系统暂时销毁 Activity

当 Activity 进入已销毁状态时,与 Activity 生命周期相关联的所有生命周期感知型组件都将收到 ON_DESTROY 事件。这时,生命周期组件可以在 Activity 被销毁之前清理所需的任何数据。

您应使用 ViewModel 对象来包含 Activity 的相关视图数据,而不是在您的 Activity 中加入逻辑来确定 Activity 被销毁的原因。如果因配置变更而重新创建 Activity,ViewModel 不必执行任何操作,因为系统将保留 ViewModel 并将其提供给下一个 Activity 实例。如果不重新创建 Activity,ViewModel 将调用 onCleared() 方法,以便在 Activity 被销毁前清除所需的任何数据。

您可以使用 isFinishing() 方法区分这两种情况。

如果 Activity 即将结束,onDestroy() 是 Activity 收到的最后一个生命周期回调。如果由于配置变更而调用 onDestroy(),系统会立即新建 Activity 实例,然后在新配置中为新实例调用 onCreate()。

onDestroy() 回调应释放先前的回调(例如 onStop())尚未释放的所有资源。

Activity 状态和从内存中弹出

系统会在需要释放 RAM 时终止进程;系统终止给定进程的可能性取决于当时进程的状态。反之,进程状态取决于在进程中运行的 Activity 的状态。表 1 展示了进程状态、Activity 状态以及系统终止进程的可能性之间的关系。

系统终止进程的可能性

进程状态

Activity 状态

较小

前台(拥有或即将获得焦点)

已创建

已开始

已恢复

较大

后台(失去焦点)

已暂停

最大

后台(不可见)

已停止

已销毁

表 1. 进程生命周期和 Activity 状态之间的关系

系统永远不会直接终止 Activity 以释放内存,而是会终止 Activity 所在的进程。系统不仅会销毁 Activity,还会销毁在该进程中运行的所有其他内容。如需了解如何在系统启动的进程被终止时保留和恢复 Activity 的界面状态,请参阅保存和恢复 Activity 状态。

用户还可以使用“设置”下的“应用管理器”来终止进程,以终止相应的应用。

如需详细了解一般进程,请参阅进程和线程。如需详细了解进程生命周期如何与其中 Activity 的状态相关联,请参阅相应页面的进程生命周期部分。

保存和恢复瞬时界面状态

用户期望 Activity 的界面状态在整个配置变更(例如旋转或切换到多窗口模式)期间保持不变。但是,默认情况下,系统会在发生此类配置更改时销毁 Activity,从而清除存储在 Activity 实例中的任何界面状态。同样,如果用户暂时从您的应用切换到其他应用,并在稍后返回您的应用,他们也希望界面状态保持不变。但是,当用户离开应用且您的 Activity 停止时,系统可能会销毁该应用的进程。

当 Activity 因系统限制而被销毁时,您应组合使用 ViewModel、onSaveInstanceState() 和/或本地存储来保留用户的瞬时界面状态。如需详细了解用户期望与系统行为,以及如何在系统启动的 Activity 和进程被终止后最大程度地保留复杂的界面状态数据,请参阅保存界面状态。

本部分概述了实例状态的定义,以及如何实现 onSaveInstance() 方法,该方法是对 Activity 本身的回调。如果界面数据简单且轻量,例如原始数据类型或简单对象(比如 String),您可以单独使用 onSaveInstanceState() 使界面状态在配置更改和系统启动的进程被终止时保持不变。但在大多数情况下,您应使用 ViewModel 和 onSaveInstanceState()(如保存界面状态中所述),因为 onSaveInstanceState() 会产生序列化/反序列化费用。

实例状态

在某些情况下,您的 Activity 会因正常的应用行为而被销毁,例如当用户按下返回按钮或您的 Activity 通过调用 finish() 方法发出销毁信号时。当您的 Activity 因用户按下返回按钮或因其自行结束而被销毁时,系统和用户对该 Activity 实例的概念将永远消失。在这些情况下,用户的期望与系统行为相匹配,您无需完成任何额外工作。

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

系统用于恢复先前状态的已保存数据称为实例状态,是存储在 Bundle 对象中的键值对集合。默认情况下,系统使用 Bundle 实例状态来保存 Activity 布局中每个 View 对象的相关信息(例如在 EditText 微件中输入的文本值)。这样,如果您的 Activity 实例被销毁并重新创建,布局状态便会恢复为其先前的状态,且您无需编写代码。但是,您的 Activity 可能包含您要恢复的更多状态信息,例如追踪用户在 Activity 中的进程的成员变量。

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

Bundle 对象并不适合保留大量数据,因为它需要在主线程上进行序列化处理并占用系统进程内存。如需保存大量数据,您应组合使用持久性本地存储、onSaveInstanceState() 方法和 ViewModel 类来保存数据,正如保存界面状态中所述。

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

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

如需保存 Activity 的其他实例状态信息,您必须替换 onSaveInstanceState(),并将键值对添加到您的 Activity 意外销毁时事件中所保存的 Bundle 对象中。替换 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);

}

注意:当用户显式关闭 Activity 时,或者在其他情况下调用 finish() 时,系统不会调用 onSaveInstanceState()。

如需保存持久性数据(例如用户首选项或数据库中的数据),您应在 Activity 位于前台时抓住合适机会。如果没有这样的时机,您应在执行 onStop() 方法期间保存此类数据。

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

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

因为无论系统是新建 Activity 实例还是重新创建之前的实例,都会调用 onCreate() 方法,所以在尝试读取之前,您必须检查状态 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

}

// ...

}

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 中获取返回结果,您可以使用

Intent 和 Intent 过滤器。

startActivity()

如果新启动的 Activity 不需要返回结果,当前 Activity 可以通过调用

在自己的应用中工作时,您通常只需启动已知 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。如果有多个 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 中提供的字符串数组,并将该数组放入电子邮件撰写表单的“收件人”字段。在这种情况下,电子邮件应用的 Activity 会启动,并且当用户完成操作时,您的 Activity 会继续运行。

startActivityForResult()

有时,您会希望在 Activity 结束时从 Activity 中获取返回结果。例如,您可以启动一项 Activity,让用户在联系人列表中选择收件人;当 Activity 结束时,系统将返回用户选择的收件人。为此,您可以调用

当子级 Activity 退出时,它可以调用 setResult(int) 将数据返回到其父级。子级 Activity 必须始终提供结果代码,该结果代码可以是标准结果 RESULT_CANCELED、RESULT_OK,也可以是从 RESULT_FIRST_USER 开始的任何自定义值。此外,子级 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) {

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. Here we will just 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 时的操作发生顺序:

Activity A 的

Activity B 的

然后,如果 Activity A 在屏幕上不再显示,其

您可以利用这种可预测的生命周期回调顺序管理从一个 Activity 到另一个 Activity 的信息转换。

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

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

相关文章

LeetCode 2121. 相同元素的间隔之和(前缀和)

文章目录1. 题目2. 解题1. 题目 给你一个下标从 0 开始、由 n 个整数组成的数组 arr 。 arr 中两个元素的 间隔 定义为它们下标之间的 绝对差 。更正式地,arr[i] 和 arr[j] 之间的间隔是 |i - j| 。 返回一个长度为 n 的数组 intervals ,其中 interva…

在android添加数据采集,一种基于Android系统的地理信息数据采集方法与流程

本方法属于采集地理信息数据的发明,是一种基于android操作系统和gis地理信息系统进行户外地理信息数据采集的方法。背景技术:众所周知地理信息数据采集在很多行业中都有应用,比如说农业中的土地普查、城市管理中的地下管线普查、工业中的地质…

LeetCode 2124. 检查是否所有 A 都在 B 之前

文章目录1. 题目2. 解题1. 题目 给你一个 仅 由字符 a 和 b 组成的字符串 s 。 如果字符串中 每个 ‘a’ 都出现在 每个 ‘b’ 之前,返回 true ;否则,返回 false 。 示例 1: 输入:s "aaabbb" 输出&#x…

设计模式—桥接模式

前言 这里以电视遥控器为例子引出桥接模式,首先每个牌子的电视都有一个遥控器,可以设计吧遥控器作为一个抽象类,抽象类中提供遥控器的所有实现,其他具体电视品牌的遥控器都继承这个抽象类 这样的实现使得每个不同型号的电视都有自…

LeetCode 2125. 银行中的激光束数量

文章目录1. 题目2. 解题1. 题目 银行内部的防盗安全装置已经激活。 给你一个下标从 0 开始的二进制字符串数组 bank ,表示银行的平面图,这是一个大小为 m x n 的二维矩阵。 bank[i] 表示第 i 行的设备分布,由若干 ‘0’ 和若干 ‘1’ 组成。…

LeetCode 2126. 摧毁小行星(贪心)

文章目录1. 题目2. 解题1. 题目 给你一个整数 mass ,它表示一颗行星的初始质量。 再给你一个整数数组 asteroids ,其中 asteroids[i] 是第 i 颗小行星的质量。 你可以按 任意顺序 重新安排小行星的顺序,然后让行星跟它们发生碰撞。如果行星…

bzoj:2018 [Usaco2009 Nov]农场技艺大赛

Description Input 第1行:10个空格分开的整数: N, a, b, c, d, e, f, g, h, M Output 第1行:满足总重量最轻,且用度之和最大的N头奶牛的总体重模M后的余数。 Sample Input 2 0 1 5 55555555 0 1 0 55555555 55555555Sample Output 51HINT 样例…

LeetCode 2129. 将标题首字母大写

文章目录1. 题目2. 解题1. 题目 给你一个字符串 title ,它由单个空格连接一个或多个单词组成,每个单词都只包含英文字母。请你按以下规则将每个单词的首字母 大写 : 如果单词的长度为 1 或者 2 ,所有字母变成小写。否则&#xf…

LeetCode 2130. 链表最大孪生和(链表快慢指针+反转链表+双指针)

文章目录1. 题目2. 解题1. 题目 在一个大小为 n 且 n 为 偶数 的链表中&#xff0c;对于 0 < i < (n / 2) - 1 的 i &#xff0c;第 i 个节点&#xff08;下标从 0 开始&#xff09;的孪生节点为第 (n-1-i) 个节点 。 比方说&#xff0c;n 4 那么节点 0 是节点 3 的孪…

Splay初步【bzoj1503】

做了一道水题&#xff0c;把bzoj1503用Splay重新写了一下。 1 #include <bits/stdc.h>2 #define rep(i, a, b) for (int i a; i < b; i)3 #define REP(i, a, b) for (int i a; i < b; i)4 #define drep(i, a, b) for (int i a; i > b; i--)5 #define mp make…

原生html5时间组件,JFinal遇到了原生Html5时间组件格式转换问题怎么处理?

今天JBolt种子用户群里有人提问&#xff0c;JFinal针对原生Html5的日期时间选择组件的格式转换支持有问题&#xff0c;报错。于是我在JBolt的Demo中加入了这些去测试一下&#xff0c;这里使用的都是原生Html组件。Input type“text”默认就是一个简单的单行文本输入框。如果修改…

LeetCode 2131. 连接两字母单词得到的最长回文串

文章目录1. 题目2. 解题1. 题目 给你一个字符串数组 words 。words 中每个元素都是一个包含 两个 小写英文字母的单词。 请你从 words 中选择一些元素并按 任意顺序 连接它们&#xff0c;并得到一个 尽可能长的回文串 。每个元素 至多 只能使用一次。 请你返回你能得到的最长…

LeetCode 2132. 用邮票贴满网格图(DP/二维差分)

文章目录1. 题目2. 解题1. 题目 给你一个 m x n 的二进制矩阵 grid &#xff0c;每个格子要么为 0 &#xff08;空&#xff09;要么为 1 &#xff08;被占据&#xff09;。 给你邮票的尺寸为 stampHeight x stampWidth 。我们想将邮票贴进二进制矩阵中&#xff0c;且满足以下…

blue html中转换,BlueFox Free PDF to HTML Converter(PDF文件转换软件)

BlueFox Free PDF to HTML Converter是一款pdf文件转换软件&#xff0c;能直接查看PDF文件和对PDF文件进行编辑&#xff0c;支持批量进行转换&#xff0c;使用非常方便&#xff0c;操作简单&#xff0c;有需要可以下载。软件特色通过将PDF转换为HTML网页&#xff0c;您的网站访…

二、前端pink老师的CSS定位学习笔记(超详细,简单易懂)

定位(position) 1. CSS 布局的三种机制 网页布局的核心 —— 就是用 CSS 来摆放盒子位置。 CSS 提供了 3 种机制来设置盒子的摆放位置&#xff0c;分别是普通流、浮动和定位&#xff0c;其中&#xff1a; 普通流&#xff08;标准流&#xff09; 浮动 让盒子从普通流中浮起来 …

LeetCode 2133. 检查是否每一行每一列都包含全部整数

文章目录1. 题目2. 解题1. 题目 对一个大小为 n x n 的矩阵而言&#xff0c;如果其每一行和每一列都包含从 1 到 n 的 全部 整数&#xff08;含 1 和 n&#xff09;&#xff0c;则认为该矩阵是一个 有效 矩阵。 给你一个大小为 n x n 的整数矩阵 matrix &#xff0c;请你判断…

上传图片自动加水印html,html5上传多个文件并添加水印 实例源码

【实例简介】【实例截图】【核心代码】html5上传多个文件并添加水印body{font-size:12px;}a{text-decoration:none;}a,a:after{-webkit-transition:all 0.3s;-moz-transition:all 0.3s;transition:all 0.3s;}a.btn i{display:block;width:100%;height:100%;position:relative;z…

LoadRunner培训初级教程

一 LoadRunner简介 1.1 Loadrunner介绍 LoadRunner 是 HP Mercury Interactive用来测试应用程序性能的工具 LoadRunner 通过模拟一个多用户并行工作的环境来对应用程序进行负载测试。通过使用最少的硬件资源&#xff0c;这些虚拟用户提供一致的、可重复并可度量的负载&#xf…

android model 设计,Android model层设计

model层在开发app的过程中&#xff0c;不管是使用了mvp还是mvc甚至mvvm模式,model层的设计基本都是一样的&#xff0c;model层可以被称为数据层&#xff0c;它的主要任务就是为上层提供各种的数据服务&#xff0c;上层完全不需要关心这些数据是来自网络&#xff0c;还是内存&am…

LeetCode 2134. 最少交换次数来组合所有的 1 II(数组*2 + 滑动窗口)

文章目录1. 题目2. 解题1. 题目 交换 定义为选中一个数组中的两个 互不相同 的位置并交换二者的值。 环形 数组是一个数组&#xff0c;可以认为 第一个 元素和 最后一个 元素 相邻 。 给你一个 二进制环形 数组 nums &#xff0c;返回在 任意位置 将数组中的所有 1 聚集在一…