Android fragments Android导航选项卡:恢复片段视图状态

Android fragments Android导航选项卡:恢复片段视图状态,android-fragments,android-tabs,Android Fragments,Android Tabs,我试图理解在导航选项卡中使用片段时如何保持片段视图状态。在我的努力中,我遇到了两个我找不到合适解决方案的问题 我有两个选项卡,选项卡1和选项卡2。Tab1的布局由FragmentA定义,Tab2的布局由FragmentB定义。 我遵循了给定的方法(编辑:自提出此问题以来,文档已更改) 第一个问题:即使我的视图有ID,当片段重新附着时(在选项卡开关旋转后),它们的状态也不会完全恢复。特别是:ID为的EditText确实会保存其输入的文本,但不会保存其启用状态。此外,即使按钮具有ID,如果按钮处于启

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

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

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

  • 切换选项卡时,请使用
    hide()/show()
    而不是
    attach()/detach()
  • onPause()
    中,通过
    getView()
    将当前片段视图状态保存在片段的
    视图
    实例变量中。在
    onCreateView(Bundle savedInstanceState)
    中,检查此字段是否为非空,如果为空,则返回此字段的值。这个解决方案似乎有问题,有人告诉我,它可能会在我的应用程序中引入内存泄漏
  • <强>第二个问题:< /强>考虑以下用户交互: 用户从Tab1开始,进行一些更改,使Tab1的视图状态与默认状态不同(我们希望片段通过tabswitches和device tilts保存此视图状态)。 然后用户转到Tab2。用户然后倾斜她/他的设备(仍在Tab2处)。 然后用户切换到Tab1(在新的屏幕方向)。


    现在,问题是:当用户最初从Tab1切换到Tab2时,片段被分离,因此其视图被丢弃(即使片段实例仍然存在)。当用户随后倾斜设备时,该活动——以及与之相关的
    FragmentA
    FragmentB
    都会被破坏。由于此时,
    FragmentA
    不再具有视图(请记住:它已分离),因此在调用
    FragmentA.onSaveInstanceState(Bundle savedInstanceState)
    期间,我们无法保存其视图元素的状态(例如,启用/禁用了哪些按钮)。在这种情况下,如何恢复片段视图状态?是否将每个视图元素的不同状态标志保存为SharedReference的唯一可行解决方案?这对于这样的“日常工作”来说似乎太复杂了。

    问题1:

    默认情况下,Android不会保存您的视图启用状态。似乎只有直接受用户操作影响的东西(没有额外的代码)才会被保存。对于普通视图和TextView(EditText是其子类),设置了(if)

    如果你想保存其他任何东西,你必须自己去做。是一个带有一些答案的问题,说明了如何实现自定义视图状态保存。如果遵循该方法,则可以坚持使用“附加/分离”

    问题2:

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

    旁注: 当您尝试旋转时,文档中的文件似乎有一些问题。TablListener的生存期与“活动”的生存期相同-每次旋转时都会创建一个新的生存期。这意味着每次旋转时,它也会丢失对片段的内部引用。添加的片段会自动重新创建,因此TabListener无需在旋转后尝试创建新实例并添加它。相反,它不应该使用内部引用,而应该在片段管理器中查找带有适当标记的片段。旋转后,它仍然存在


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

    非常感谢-很好的解释。然而,事情对我来说还不是很清楚。我已经看到了你提到的答案,但我没有理解它的用途。什么是“自定义视图”?我的片段视图状态只包含内置视图(如编辑文本、按钮等)。因此,我没有扩展任何视图类——我只是在xml布局文件中构建了片段视图。如何将答案中提供的示例代码连接到不使用任何用户定义视图的布局(假设自定义视图对于android就像用户定义控件对于ASP.NET一样)?@jvmk要使用View.onSaveInstanceState(),需要对视图进行子类化并重写该方法。然后,布局XML需要引用这些新视图,而不是EditText/Button.Woah,这太疯狂了。我认为恢复内置视图的视图状态将是一项经常重复的任务,这足以作为标准功能得到支持。假设我应该写一个库供将来使用。谢谢你在这里帮助我。这已经困扰了我2个星期了,HEH。请考虑包括一些关于你的答案的信息,而不是简单的帖子。
    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) {
    }