Android 10 - 奇怪的活动生命周期
Posted
技术标签:
【中文标题】Android 10 - 奇怪的活动生命周期【英文标题】:Android 10 - Weird activity lifecycle 【发布时间】:2020-12-09 11:55:13 【问题描述】:我在 android 10 上遇到了一个奇怪的问题,当我开始新的横向活动时,下面的活动将重新创建。
假设有两个Activity
类:
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
又重新创建了?
正如我在我的设备中看到的,在ActivityB
变得可见之前,ActivityA
旋转到横向模式,当ActivityB
退出时,ActivityA
再次旋转回到纵向模式。这种行为可能会导致ActivityA
一次又一次地重新创建。
乱七八糟,你知道如何防止ActivityA
在这种情况下重新创建,或者这是Android本身的错误吗?
更新 1
我可以轻松处理ActivityA
上的配置更改,问题是ActivityA
有一个非常复杂的视图结构,没有必要重新创建它会导致UI滞后,而且活动的生命周期回调混乱也会导致逻辑中断。
更新 2
我刚刚发现recreate()
方法被AppCompatDelegateImpl
类调用了两次,这就是为什么我得到奇怪的生命周期行为:
【问题讨论】:
从活动 A 开始带有标志单顶的活动 B 以强制活动 A 关闭 @alokHarman 这个评论毫无意义。 请提供简单的示例代码以及全屏活动的方式 alokHarman 的意思是为活动设置 android:launchMode=singleTop (q.v. developer.android.com/guide/topics/manifest/activity-element),它应该通过重新触发意图来重用活动。但我怀疑它是否会在这里起作用,因为配置更改会导致破坏(请参阅下面的答案) 【参考方案1】:对于这种行为,您可能无能为力。如果不会给您带来太多问题,我会建议以下内容:
将android:configChanges="orientation"
添加到ActivityA
的清单条目中
在ActivityA
中实现onConfigurationChanged()
并自行处理方向更改
这将防止 Android 在方向更改期间终止并重新创建 ActivityA
。
【讨论】:
还有一个问题,我严重依赖方法onResume
来确定堆栈顶部可见的活动,但是在这种行为中,ActivityA#onResume 在它位于 ActivityB 后面时被调用,它导致了很多逻辑问题。【参考方案2】:
这看起来像是一个特定于设备的错误。
我在 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 将在运行时配置更改时重新创建。
您可以做的是在您的活动中覆盖onConfigurationChanged(Configuration)
并记录配置对象以查看更改了哪些设备配置。可能是Orientation
、Screen size
、ScreenLayout
或Keyboard availability
【讨论】:
感谢您在您的设备上进行测试,我只是运行了一个示例项目并发现它不是因为方向问题,请参阅我的更新。【参考方案3】:不仅你面临这个问题(很多人都面临这个问题),这是一个需要修复的错误,实际上它不应该被弄乱我可以知道你使用的是哪个设备吗?您可以在评论中告诉。
【讨论】:
我的设备是三星M10,android 10,One UI 2.0 您知道其他地方讨论过的任何相关问题吗?【参考方案4】:在横向/纵向上重新创建活动是 Android 的一项设计功能(不是错误),因为以编程方式重绘 UI 比计算元素的重新定位/调整大小更容易。即使没有 B,您也应该在 A 上翻转方向时获得相同的效果。Android 文档 (https://developer.android.com/guide/components/activities/state-changes#cco) 中也很好地描述了这一点
这应该不是太大的问题,只要您不保留对活动本身的任何引用;此时的资源已被缓存,因此几乎没有闪存 I/O,大部分工作将是重新创建视图。
【讨论】:
在我看来更像是一个错误,如果 ActivityA 仅设计用于纵向模式怎么办?又怎么能解释为什么在ActivityB#onResume之后调用ActivityA#onResume(ActivityA在ActivityB后面)。 根据您的说法,ActivityA 可以是纵向或横向(您注明“未指定”)。仅将其设为纵向应该会停止过渡。【参考方案5】:按照官方 Activity Lifecycle onDestroy() 文档中的说明,默认情况下,每次轮换后都会重新创建 Activity。
如果您希望 Activity 的 UI 状态在整个配置更改(例如旋转)期间保持不变,则应使用 ViewModel、onSaveInstanceState() 和/或本地存储的组合来保留用户的瞬态 UI 状态,如在Saving and restoring transient UI state
您可以使用 AndroidManifest 中活动标签的配置更改属性覆盖此行为。有关更多详细信息和不同选项,请参阅Handle configuration changes
最后,您可以在此处了解有关Activity Lifecycle in Context of Screen Rotation 的更多信息。
【讨论】:
以上是关于Android 10 - 奇怪的活动生命周期的主要内容,如果未能解决你的问题,请参考以下文章