我应该如何在支持屏幕旋转的同时添加我的初始片段?

How should I add my initial fragment while supporting screen rotations?

当我的应用程序启动时,我动态地将片段实例(例如,fragment1)添加到未添加到返回堆栈的事务中的内容布局。此片段显示一些已通过 newInstance(List<Obj>) 静态方法传递给它的缓存数据。在 onSaveInstanceState() 中,我保存了数据,以便在重新创建片段时可以显示它。

现在假设我不重新创建片段。假设我用第二个片段替换它,比如 fragment2(这次将事务添加到返回堆栈),执行两次屏幕旋转,然后按返回。该应用程序将弹出返回堆栈并尝试再次显示 fragment1,这将依次尝试显示 List<Obj>,这将是 null,因此将抛出 NullPointerException

我明白这是因为 fragment1 实例一开始就没有保存过,因为它不在返回堆栈中,并且在设备旋转时也没有显示。

我的问题是,在这种情况下支持屏幕旋转的最合适方式是什么?我可以将初始交易保存在后台堆栈中,并在弹出后台堆栈之前让 onBackPressed() 验证 getSupportFragmentManager().getBackStackEntryCount() >= 1(我不希望弹出初始交易,因为 fragment1 是我的初始交易屏幕),但我认为这不是正确的方法。有什么想法吗?

如果您的列表不是很大,可以将其传递到 onSaveInstanceState 中的捆绑包并在 onRestoreInstanceState 中检索它。即使片段不在前台,仍应在 destruction/recreation 上调用这些方法。但是,如果数据非常大或不可序列化或不可打包,则这不是一个选项。

来自docs:

If restarting your activity requires that you recover large sets of data, re-establish a network connection, or perform other intensive operations, then a full restart due to a configuration change might be a slow user experience. [...] In such a situation, you can alleviate the burden of reinitializing your activity by retaining a Fragment when your activity is restarted due to a configuration change. This fragment can contain references to stateful objects that you want to retain.

听起来在这种情况下您可能希望保留包含 List<Obj> 的片段。问题是,这需要您的 activity 检查它可以在 onCreate 中创建的所有保留片段,以查看它们是否已经存在,并且您已经表达了对这种情况下可维护性的担忧。

最后,您可以通过在 android 清单中使用 android:configChanges 参数声明您打算自行处理方向更改。这将防止您的 activity(及其关联的片段及其成员)在方向更改中被破坏和重新创建,而系统将在您的 activity 中调用 onConfigurationChanged。如果您不重写 onConfigurationChanged,方向改变时除了屏幕会旋转外什么也不会发生。 Google 不鼓励这样做,除其他原因外,因为它是一种代码味道。求助于此意味着您不能很好地处理状态更改,并且如果您的 activity 在用户查看其他内容时被破坏,您的状态将无法正确保存。

编辑:

如果您的片段通过其参数包接收数据,例如调用 setArguments(),则该包“will be retained across fragment destroy and creation.