关于android:如何在单/双窗格布局中管理UI状态和后端堆栈

How to manage UI state and the back stack in a single/dual-pane layout

我很难理解如何在典型的列表详细设计模式中正确地管理Fragment

我的布局工作良好,对于景观视图(双窗格)的结构如下:

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout ... >
    <FrameLayout android:id="@+id/list" ... />
    <FrameLayout android:id="@+id/container" ... />
</LinearLayout>

像这样的纵向视图(单窗格):

1
2
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="@+id/container" ... />

我在res/values-w600dp/中还有一个refs.xml以确保根据设备的屏幕宽度加载适当的布局。

选择列表项时,横向视图应并排显示列表和详细信息,而纵向视图应仅全屏显示详细信息。如果未选择任何内容,则横向视图应在左侧显示左侧,在右侧显示空白,而纵向视图应仅在全屏显示列表。

example

然而,我遇到的问题是:

  • 我是否使用"主"Activity作为列表+可选细节布局,以及其他"细节"Activity作为肖像,仅细节布局?这似乎就是片段引导示例所做的。我已经获得了一般工作的许可,但是当方向改变时,我如何保持细节片段的状态呢?

    考虑上面显示的相反情况——从纵向旋转到横向,而细节是可见的,这意味着细节Activity需要finish()ed,以便主Activity可以显示两个窗格的布局,但这也会破坏细节片段及其savedInstanceState。如果用户在详细信息片段的EditText字段中键入了信息,那么旋转设备,当我将其添加到主(两个窗格)Activity时,如何保留详细信息片段的整个用户界面状态?

  • 我是否只使用一个Activity并自己管理Fragment?这允许我在方向改变时保留细节用户界面的状态(因为Android会自动处理这个问题),但当它进入后堆栈时会变得混乱。

    考虑图像中的情况——当细节可见时从横向旋转到纵向,应该显示"显示细节"单个窗格,但如何正确管理后堆栈和ActionBar主图标以显示列表单个窗格?旋转回横向也需要撤销我之前所做的任何后堆栈操作,因为两个片段将同时可见。

经过更多的搜索,我发现了两个类似的问题(在方向改变时从双窗格切换到单窗格,维护片段堆栈,并在活动之间保留片段状态),但我的情况略有不同,因为我不是在尝试更新此功能,而是预先为其进行最佳计划。我错过了什么?当然,Android可以同时管理后堆栈(如多个Activity情况)和用户界面状态(如单个Activity情况),对吗?


我通过多个活动路线解决了这个问题。请参阅我对"在活动之间保留片段状态"的回答。

关键是使用FragmentManager.saveFragmentInstanceState()保存片段的UI状态,当在另一个活动中实例化同一个片段时,使用Fragment.setInitialSavedState()恢复它。

出于我的目的,我发现我需要在两种情况下保存UI状态。我在片段中创建了一个助手方法public void saveState(),并在使用replace()将片段的新实例附加到双窗格布局之前,从片段自己的onPause()方法以及"主"活动调用它。

我仍然感兴趣的是知道这种类型的单/双窗格布局方案所需的后堆栈操作是否可行,或者单活动方法是否需要重写onBackPressed,并手动模拟后堆栈。


只使用一个活动是可能的,但是当你自己进行纵向定位时,你必须管理后台。

正如您描述应用程序的行为一样,可能有4种状态:

  • 状态A:肖像,显示列表片段。
  • 状态B:肖像,显示细节片段和后堆栈上的列表片段。
  • 状态C:横向,左侧显示列表片段,右侧显示空白。
  • 状态D:横向,并排显示列表片段和细节片段。

假设你在状态D(有两个片段,我们称它们为fa和fb),你改变了手机的方向。下面的状态应该是状态B,但问题是您的肖像布局只有一个FrameLayout。将以下内容用作单窗格布局:

1
2
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout android:id="@+id/list" ... />

安卓将重新创建fa,并将其附加到FrameLayout上。另一方面,FB也将被重新创建,但没有关联的容器,因此不会显示出来。此时,您可以创建另一个片段FB2,其内容与FB相同,并使用它来替换FA。你的后背包里会有FA-FB2,FB也会被藏起来。

如果你再次改变方向(期望状态D),你可以用onSaveInstanceState()把fb2从backstack中弹出到popBackStack(),这样就又有了fa和fb。在删除FB2之前,您可能还需要将其内容复制到FB。当应用程序再次处于D状态时,FB将具有其框架布局。

还有一些其他的过渡和情况需要你去处理,但是主要的想法是。

这不是一个非常优雅的解决方案,所以我确信它必须是一种更好的、也许更有效的(例如,不复制片段)方法来解决这个问题。