Android Lifecycle ViewModel横屏锁屏解锁后未持久化问题求助
我刚梳理了你遇到的这个ViewModel丢失的问题,咱们一步步来拆解:
现象复现与核心问题
你开发的测试应用包含FragmentActivity、ViewModel、ViewModelFactory,并配置了对应Manifest项,复现路径是:
- 将应用切换至横屏模式
- 锁屏后再解锁
此时出现两个关键异常:
- ViewModel实例完全丢失
- Activity被销毁重建了两次
日志输出已经验证了这个行为,但你预期Jetpack架构库应该能处理这类标准配置变更场景(比如竖屏状态下锁屏解锁的正常情况)。
可能的原因分析
这种异常的两次重建+ViewModel丢失,通常和以下几个点有关:
1. Manifest配置的遗漏或错误
检查你的AndroidManifest.xml中对应Activity的configChanges属性,是否遗漏了orientation或者screenSize?如果你的targetSdkVersion >= 13,screenSize会随orientation变更一起触发,必须同时处理才能避免系统误判配置变更类型,进而触发额外的Activity重建。
2. ViewModel绑定的生命周期范围错误
你使用的是FragmentActivity,务必确保获取ViewModel时绑定的是Activity自身的生命周期,而非某个Fragment或临时生命周期对象。比如在Fragment中如果错误用this而非requireActivity()获取ViewModel,就可能在Activity重建时丢失实例。
正确的获取方式示例:
// 在FragmentActivity内部获取 val viewModel = ViewModelProvider(this, YourViewModelFactory())[YourTestViewModel::class.java] // 在Fragment中绑定Activity生命周期 val viewModel = ViewModelProvider(requireActivity(), YourViewModelFactory())[YourTestViewModel::class.java]
3. 锁屏触发的额外配置变更叠加
部分设备在锁屏时会触发uiMode变更(比如自动切换夜间模式),如果你的应用没在configChanges中声明uiMode,这个变更会和横屏的orientation变更叠加,导致系统连续触发两次重建:第一次是横屏切换,第二次是锁屏/解锁触发的uiMode变更,ViewModel可能因为两次重建的生命周期衔接问题丢失。
建议的解决步骤
修正Manifest的configChanges配置
如果希望依赖Jetpack处理配置变更,不要声明orientation/screenSize/uiMode;如果需要自行处理适配,完整声明相关项:<activity android:name=".YourTestActivity" android:configChanges="orientation|screenSize|uiMode"> </activity> > 注意:除非有特殊UI适配需求,不建议随意声明`configChanges`——ViewModel的设计初衷就是帮你处理配置变更下的状态保留。确认ViewModel的绑定范围
检查所有获取ViewModel的代码,确保生命周期所有者是FragmentActivity本身,避免绑定到临时的生命周期对象。排查设备特定行为
部分厂商的定制ROM会对锁屏/横竖屏切换做特殊处理,导致额外的Activity重建,可以在不同设备上测试,确认是否是设备特定问题。
总结
Jetpack ViewModel确实应该处理标准的配置变更场景(比如竖屏锁屏解锁),但横屏+锁屏的复合场景可能因为叠加的配置变更触发了非预期的重建流程。按照上面的步骤排查,应该能定位到问题所在。
内容的提问来源于stack exchange,提问作者dkarmazi

