Android 10 - 奇怪的 activity 生命周期

Android 10 - Weird activity lifecycle

我在 Android 10 上遇到了一个奇怪的问题,当我开始新景观 activity 时,下面的 activity 将重新创建。

假设有两个 Activity classes:

ActivityA: orientation = unspecified
ActivityB: orientation = force landscape, full screen, opaque

如果我从 ActivityA 开始 ActivityB,生命周期事件的日志:

D/ActivityA: onPause() called
D/ActivityB: onCreate() called
D/ActivityB: onStart() called
D/ActivityB: onResume() called
D/ActivityA: onStop() called
D/ActivityA: onDestroy() called
D/ActivityA: onCreate() called
D/ActivityA: onStart() called
D/ActivityA: onResume() called
D/ActivityA: onPause() called
D/ActivityA: onStop() called

可以清楚地看到ActivityA被重新创建了,而且ActivityA#onResumeActiviyB#onResume之后被调用了??

好的,现在我们在堆栈顶部有 ActivityB,然后我按下后退按钮:

D/ActivityB: onPause() called
D/ActivityA: onStart() called
D/ActivityA: onResume() called
D/ActivityA: onPause() called
D/ActivityA: onStop() called
D/ActivityA: onDestroy() called
D/ActivityA: onCreate() called
D/ActivityA: onStart() called
D/ActivityA: onResume() called
D/ActivityB: onStop() called
D/ActivityB: onDestroy() called

ActivityA又重新创建了?

正如我在我的设备中看到的那样,有一个动画 ActivityAActivityB 变得可见之前旋转到横向模式,并且当 ActivityB 退出时,ActivityA 再次旋转返回纵向模式。此行为可能会导致 ActivityA 一次又一次地重新创建。

乱七八糟,你知道如何防止ActivityA在这种情况下重新创建,或者这是Android本身的错误?

更新 1

我可以轻松处理 ActivityA 上的配置更改,问题是 ActivityA 具有非常复杂的视图结构,不必要地重新创建它会导致 UI 滞后,而且 activity乱七八糟的生命周期回调也导致逻辑混乱

更新 2

我刚刚发现 recreate() 方法被 AppCompatDelegateImpl class 调用了两次,这就是为什么我得到奇怪的生命周期行为:

不只是你遇到这个问题(很多人都是)这是一个需要修复的错误,实际上不应该被弄乱我可以知道你使用的是哪种设备吗?在评论中你可以告诉。

对于这种行为,您可能无能为力。如果不会给您带来太多问题,我会提出以下建议:

  • android:configChanges="orientation" 添加到 ActivityA
  • 的清单条目
  • ActivityA 中实施 onConfigurationChanged() 并自行处理方向更改

这将防止 Android 在方向更改期间杀死和重新创建 ActivityA

在 landscape/portrait 上重新创建活动是 Android 的一项功能(不是错误),这是设计造成的,因为以编程方式重绘 UI 比找出 [=16] 更容易=] 的元素。即使没有 B,只要在 A 上翻转方向也应该得到相同的效果。这在 Android 文档 (https://developer.android.com/guide/components/activities/state-changes#cco)

中也有详细描述

这应该不是什么大问题,只要您不保留对 activity 本身的任何引用;此时的资源已经缓存,因此几乎没有闪存 I/O,大部分工作将重新创建视图。

Activity 默认情况下在每次旋转后重新创建,正如官方 Activity 生命周期 onDestroy() 文档中所述。

如果您希望 activity 的 UI 状态在配置更改(例如旋转)期间保持不变,您应该使用组合保留用户的瞬态 UI 状态ViewModel 的 onSaveInstanceState(),and/or 本地存储,如 Saving and restoring transient UI state

中所述

您可以使用 AndroidManifest 中 activity 标记的配置更改属性覆盖此行为。有关详细信息和不同的选项,请参阅 Handle configuration changes

最后,您可以在此处了解有关 Activity Lifecycle in Context of Screen Rotation 的更多信息。

这看起来像一个 device-specific 错误。

我在 Pixel 3a(API 29 和 30)模拟器上尝试了您的代码。这是我得到的:

ActivityA 开始 ActivityB 时:

D/MainActivityA: onPause() called
D/MainActivityB: onCreate() called
D/MainActivityB: onStart() called
D/MainActivityB: onResume() called
D/MainActivityA: onStop() called

按下后退按钮:

D/MainActivityB: onPause() called
D/MainActivityA: onStart() called
D/MainActivityA: onResume() called
D/MainActivityB: onStop() called
D/MainActivityB: onDestroy() called

您应该file an issue使用适当的Android构建和使用的设备

关于问题更新2的思考:

日志显示正在调用 onConfigurationChanged(Configuration)Documentation 指出 Activity 将在运行时配置更改时重新创建。

您可以做的是覆盖 Activity 中的 onConfigurationChanged(Configuration) 并记录配置对象以查看更改了哪些设备配置。它可能是 OrientationScreen sizeScreenLayoutKeyboard availability