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#onResume
在ActiviyB#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
又重新创建了?
正如我在我的设备中看到的那样,有一个动画 ActivityA
在 ActivityB
变得可见之前旋转到横向模式,并且当 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)
并记录配置对象以查看更改了哪些设备配置。它可能是 Orientation
、Screen size
、ScreenLayout
或 Keyboard availability
我在 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#onResume
在ActiviyB#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
又重新创建了?
正如我在我的设备中看到的那样,有一个动画 ActivityA
在 ActivityB
变得可见之前旋转到横向模式,并且当 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)
并记录配置对象以查看更改了哪些设备配置。它可能是 Orientation
、Screen size
、ScreenLayout
或 Keyboard availability