对 Activity 生命周期感到困惑

问题描述

我对 Activity 生命周期的某些方面有些困惑。

假设您有两个活动 A 和 B,A 是启动活动。您启动应用程序,然后 A 通过 onCreate()、onStart() 等。在 onCreate() 之前实例化活动类对象,因此您可以在 onCreate() 中创建您需要的任何子项。

然后您使用 startActivity() 来启动活动 B。A 经历 onPause() 等,B 像 A 一样经历启动过程。

现在说你想回到 A. 两种方式 - 完成()(或 onBackpressed() / 后退按钮似乎做同样的事情),或者使用 startActivity() 来启动 A。A 应该在历史堆栈,除非使用 'noHistory' 创建。

使用finish() 或返回,A 现在运行onRestart()、onStart() 等——而不是onCreate()——这似乎是有道理的。也就是说,除非它由于内存限制而被杀死,同时它会从原来的位置继续运行。但是,对于 startActivity(),它总是通过 onCreate()、onStart() 等来代替。这意味着第一次在 onCreate() 中设置的所有内容都会再次完成。假设它在历史堆栈上,为什么不走 onRestart() 路线?

是否是这种情况,每当通过 startActivity() 启动活动时,(1) 类对象实际上总是重新实例化,因此必须在 onCreate() 中重新创建其他所有挂起的对象,或者,(2) 是之前使用的实例化(如果存在),因此可以在 onCreate() 中检测到它并将通过 onCreate() 的传递有效地视为 onRestart() 吗?

解决方法

假设它在历史堆栈中,为什么不走 onResume() 路线?

因为调用 startActivity,默认情况下会创建 Activity 的新实例。每个实例贯穿整个生命周期。因此,在您的示例中,它并不是真正的 A -> B -> A。它更像是 A1 -> B -> A2,其中 A1 和 A2 是活动 A 的实例

当您启动 A 的第二个实例时,就像从 A 的第一个实例创建 B 一样。这是一个全新的对象,因此必须从头开始创建。

是否是这种情况,每当通过 startActivity() 启动活动时,(1) 类对象实际上总是重新实例化,因此必须在 onCreate() 中重新创建其他所有挂起的对象,或者,(2) 是之前使用的实例化,因此可以在 onCreate() 中检测到它并将通过 onCreate() 的传递有效地视为 onResume() 吗?

如上所述,它通常 (1)。这是默认行为。但是,您可以使用正确的 launch mode flags 使应用导航到 A 的现有实例。在这种情况下,现有实例将被带到堆栈的前面,通过 onStartonResume(跳过 onCreate,因为它已经存在),但随后也会调用 { {3}} 接收 - 好吧 - 再次启动它的新意图。

在这种情况下,它是 A -> B -> A,因为您导航到 A 的原始实例已经存在,而不是创建一个新实例。


编辑

进一步观察,如果 A 以 startActivityForResult() 开始 B,是否会得到类似的结果?即结果会返回到 A 的原始实例吗?

“相似”但不相同。主要区别在于您的导航堆栈会发生什么。

如果你做 A -> startForResult -> B,然后完成 B 并返回你的结果,你就剩下 A。

如果你做 A -> B -> startSingleTop -> A 那么你最终会在堆栈中得到 B 和 A。所以如果你从 A 点退缩,你最终会回到 B 点。

另外,请记住,对于 Android,您几乎永远无法保证返回任何活动的“原始实例”。当 A 在后台而您在 B 上时,如果需要内存,系统可以杀死 A 的该实例。无论您使用单个任务启动 A 还是在 startForResult 之后返回它,您都可能返回到一个新的实例

我看这个的原因是让 B 像 A 的对话框一样。即,运行 A,去 B 并调整一些东西,回到 A 并从停止的地方继续

对于这种情况,startActivityForResult 将是最好的行动方案。一般来说,除非真的有必要并且你真的知道自己在做什么,否则避免使用启动模式标志 - 它会很快变得复杂。