12

我试图了解在导航选项卡中使用片段时如何保留片段视图状态。在我的努力中,我遇到了两个我找不到任何合适解决方案的问题。

我有两个选项卡,Tab1 和 Tab2。Tab1 的布局由 定义FragmentA,Tab2 的布局由 定义FragmentB。我遵循了这里给出的方法(编辑:自从提出这个问题以来,文档已经改变)。

第一个问题:即使我的视图有 ID,但在重新附加片段时(在选项卡开关旋转之后),它们的状态并没有完全恢复。特别是:EditText带有 ID的确实会保存其输入的文本,但不会保存其启用状态。此外,即使按钮具有 ID,启用或禁用按钮也不会保存。对于这个问题,我发现了两种可能的解决方法:

  1. 在切换标签时使用hide()/show()而不是。attach()/detach()
  2. 在中onPause(),将当前片段视图状态保存在片段的View实例变量中getView()onCreateView(Bundle savedInstanceState)检查该字段是否为非空,如果是,则返回该字段的值。这个解决方案看起来很老套,有人告诉我它还可能在我的应用程序中引入内存泄漏。

第二个问题:考虑以下用户交互:用户从 Tab1 开始并进行一些更改,使 Tab1 的视图状态与其默认状态不同(我们希望片段通过 tabswitches 和设备倾斜保存此视图状态) . 用户然后转到 Tab2。然后用户倾斜她/他的设备(仍然在 Tab2)。用户然后切换到 Tab1(在新的屏幕方向)。现在,问题是:当用户最初从 Tab1 切换到 Tab2 时,片段被分离,因此它的视图被丢弃(即使片段实例仍然存在)。当用户然后倾斜设备时,活动 - 以及FragmentA与之FragmentB相关的活动 - 被破坏。自从FragmentA此时不再有视图(请记住:它已分离),我们无法在调用FragmentA.onSaveInstanceState(Bundle savedInstanceState). 在这种情况下如何恢复片段视图状态?将每个视图元素的不同状态标志保存为 SharedPreferences 是唯一可行的解​​决方案吗?对于这样的“日常工作”来说,这似乎太复杂了。

4

2 回答 2

8

问题1:

默认情况下,Android 不会保存您的视图启用状态。似乎只保存了直接受用户操作影响的东西(没有额外的代码)。对于普通视图,不保存任何信息,对于 EditText 是其子类的 TextView,将保存输入的文本(如果设置了freezesText)。

如果你想拯救其他任何事情,你必须自己做。是一个带有一些答案的问题,显示了如何实现自定义视图状态保存。如果您遵循这种方法,您可以坚持使用附加/分离。

问题2:

你是对的,在你的视图已经被销毁后可以调用 Fragment.onSaveInstanceState(Bundle) 。但是,这不是您应该保存视图状态的地方。在分离片段时,Android 会在销毁您的视图之前调用 View.onSaveInstanceState()。它会保存此状态并在您再次附加片段时将其返回给您。这正是您在标签之间正常翻转而没有旋转时发生的情况。分离时不调用 Fragment.onSaveInstanceState(Bundle)。即使您旋转设备,由于分离而保存的视图状态也会保留。如果按照上面的说明实现 View.onSaveInstanceState(),即使在 Tab1-Tab2-rotate-Tab1 场景中,您的视图状态也将被正确保存和恢复。

旁注:当您尝试旋转时,文档中 的示例代码似乎存在一些问题。TabListener 的生命周期与 Activity 的生命周期相同——每次旋转时都会创建一个新的。这意味着每次旋转时它也会丢失对片段的内部引用。添加的片段会自动重新创建,因此 TabListener 无需在旋转后尝试创建新实例并添加它。相反,内部引用应该只是尝试在片段管理器中找到具有适当标记的片段。旋转后它仍然存在。

另一个问题是未保存所选选项卡,但这在示例底部有说明。您可以将其保存在 Activity.onSaveInstanceState(Bundle) 中。

于 2013-03-16T17:50:20.990 回答
0
private ViewPager viewPager;
viewPager = (ViewPager) findViewById(R.id.pager);
mAdapter = new TabsPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(mAdapter);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {

        @Override
        public void onPageSelected(int position) {
            // on changing the page
            // make respected tab selected
            actionBar.setSelectedNavigationItem(position);
        }

        @Override
        public void onPageScrolled(int arg0, float arg1, int arg2) {
        }

        @Override
        public void onPageScrollStateChanged(int arg0) {
        }
    });
}

@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {
}

@Override
public void onTabSelected(Tab tab, FragmentTransaction ft) {
    // on tab selected
    // show respected fragment view
    viewPager.setCurrentItem(tab.getPosition());
}

@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {
}
于 2014-12-09T13:49:05.910 回答