【问题标题】:How to restore child fragments in TabHost/ViewPager parent fragment如何在 TabHost/ViewPager 父片段中恢复子片段
【发布时间】:2013-09-24 23:45:49
【问题描述】:

问题在下面突出显示,第一部分描述了到目前为止的工作。

我在一个活动中使用多个片段。图的上半部分显示了一个片段,例如包含一些随机内容的列表。如果我单击某处,它将打开AboutTheAppFragment。当我单击back 时,它再次显示ASingleFragment。这很有效,但这是最简单的部分:)

这是我用来打开新片段的代码。

AboutTheAppFragment aboutTheAppFragment = new AboutTheAppFragment();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(mContainer.getId(), aboutTheAppFragment, AboutTheAppFragment.class.getName());
fragmentTransaction.addToBackStack(null);

现在这是我的问题

我喜欢显示 TabHostPagerFragment 而不是 ASingleFragment,它使用 TabHost 和 ViewPager 来显示片段(见下图)。假设我有两个片段TabOneFragmentTabTwoFragment,但 ViewPager 中只显示了一个片段。这也很好用,我可以简单地在屏幕上滑动并在两个选项卡片段之间切换。但是,如果我单击某处打开AboutTheAppFragment 并再次单击back,则TabOneFragmentTabTwoFragment 两个片段都不会显示任何内容。如果我旋转设备,它会再次重新加载/恢复片段,一切正常。所以我的问题是,我怎样才能将TabOneFragmentTabTwoFragment 添加到后台,当我单击back 按钮时它们会正确显示?请注意,当我将TabOneFragment 设置为ASingleFragment 时,它的工作原理类似于场景1,然后我单击某处并再次单击返回。但是当我使用 TabHostPagerFragment 时它不起作用。

这是 TabHostPagerFragment 的一些代码 sn-ps:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    // Inflate the tabs pager fragment in the container
    View view = inflater.inflate(R.layout.fragment_tabs_pager, container, false);
    mContainer = container;

    // Set up the TabHost
    mTabHost = (TabHost) view.findViewById(android.R.id.tabhost);
    mTabHost.setup();

    // Set up the ViewPager
    mViewPager = (ViewPager) view.findViewById(R.id.pager);

    return view;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    // Now initialize the TabsAdapter which will be used to manage the tabs
    mTabsAdapter = new TabsAdapter(activity, mTabHost, mViewPager);

    // Finally add the tabs to the TabsAdapter: meal plan for today and meal plan for the week 
    mTabsAdapter.addTab(mTabHost.newTabSpec("TabOne").setIndicator("TabOne", TabOneFragment.class, null);
    mTabsAdapter.addTab(mTabHost.newTabSpec("TabTwo").setIndicator("TabTwo", TabTwoFragment.class, null);

    if (savedInstanceState != null) {
        // NEVER REACHES THIS CASE
        mTabHost.setCurrentTabByTag(savedInstanceState.getString("tab"));
    }
}

我注意到 savedInstanceState 始终为空。知道如何解决此问题并将选项卡存储在已保存的实例状态中吗?

我将不胜感激。

最好的问候,迈克尔

编辑:

片段的调用层次结构如下:

09-25 09:19:25.695: V/TabsPagerParentFragment(1820): onPause
09-25 09:19:25.695: V/TabsPagerParentFragment(1820): onStop
09-25 09:19:25.703: V/TabsPagerParentFragment(1820): onDestroyView
09-25 09:19:25.710: V/AboutTheAppFragment(1820): onAttach
09-25 09:19:25.710: V/AboutTheAppFragment(1820): onCreate: savedInstanceState == null
09-25 09:19:25.710: V/AboutTheAppFragment(1820): onCreateView: savedInstanceState == null
09-25 09:19:25.812: V/AboutTheAppFragment(1820): onViewCreated
09-25 09:19:25.812: V/AboutTheAppFragment(1820): onActivityCreated
09-25 09:19:25.812: V/AboutTheAppFragment(1820): onViewStateRestored
09-25 09:19:25.812: V/AboutTheAppFragment(1820): onStart
09-25 09:19:25.812: V/AboutTheAppFragment(1820): onResume
09-25 09:19:27.304: V/AboutTheAppFragment(1820): onPause
09-25 09:19:27.304: V/AboutTheAppFragment(1820): onStop
09-25 09:19:27.304: V/AboutTheAppFragment(1820): onDestroyView
09-25 09:19:27.304: V/AboutTheAppFragment(1820): onDestroy
09-25 09:19:27.312: V/TabsPagerParentFragment(1820): onCreateView: savedInstanceState == null
09-25 09:19:27.320: V/TabsPagerParentFragment(1820): onViewCreated
09-25 09:19:27.320: V/TabsPagerParentFragment(1820): onActivityCreated
09-25 09:19:27.328: V/TabsPagerParentFragment(1820): onViewStateRestored
09-25 09:19:27.328: V/TabsPagerParentFragment(1820): onStart
09-25 09:19:27.328: V/TabsPagerParentFragment(1820): onResume

【问题讨论】:

    标签: android android-fragments android-viewpager android-tabhost fragment-tab-host


    【解决方案1】:

    在你的 TabHostFragment、TabOneFragment 和 TabTwoFragment 的构造函数中调用:

       setRetainInstance(true);
    

    您目前没有任何东西正在“重建”片段的状态。当您将 ASingleFragment 替换为 AboutTheAppFragment 时,ASingleFragment 将被销毁并忘记,直到您按“返回”,此时系统将重新创建视图层次结构,但不会重新创建其内容。调用 setRetainInstance(true) 将告诉系统保留整个片段,包括其数据,以便可以恢复它。

    onActivityCreated() 的 saveInstanceState 在这里没有发挥作用,这是针对父 Activity 而不是子 Fragments。

    【讨论】:

    • 感谢您的回复!我尝试了你的方法,但它不起作用。我还仔细检查了是否调用了所有构造函数。我在帖子中复制了调用层次结构 - 我想知道为什么永远不会调用 TabOneFragmentTabTwoFragment 的 onDestroy 方法。任何想法?顺便说一句,我还实现了一个没有 TabHost 的寻呼机(显示图片),并且效果很好。我猜它是关于 TabHost 实现的一些具体内容:-/
    • TabHost 似乎没有正确保留其状态。如果你已经完成了 setRetainInstance(true) 那么片段不应该被破坏所以 fragment.onCreate() 不会被调用。但是他们的视图(tabhost)将被破坏,所以 onCreateView() 被调用。您在 onActivityCreated() 中将选项卡添加到适配器,但它创建了一个新的 TabAdapter,它在哪里分配给 viewPager?我很想将该代码移动到 onCreateView() 然后调用 mViewPager.setAdapter() 只是为了确保它们一起完成。
    • @NeilS 你是怎么解决的?我在 viewpager+fragmetns 中也面临同样的问题
    • 你的问题和原来的问题一模一样吗?你试过setRetainInstance(true)吗?由于这个问题很老,最好创建一个新问题 - 在此处链接它,我会看看是否可以提供帮助。
    【解决方案2】:

    我有一个复杂的布局,一个片段中有 3 个选项卡,其他片段会被切换出来。我意识到ViewpagerAdapter 将保留状态,即使您按下主页按钮。我的问题是来回切换会使子片段 UI 视图元素无效并崩溃。关键是不要将new 排除在您的ViewPagerAdapter 之外。为适配器添加空检查对我有用。另外,请务必根据您的需要分配setOffscreenPageLimit()。另外,据我了解,setRetainInstance(true); 不应该用于具有 UI 的片段,它是为无头片段设计的。

    在包含您的选项卡的片段中:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_tab, container, false);
        tabLayout = (TabLayout) view.findViewById(R.id.tablayout);
        viewPager = (ViewPager) view.findViewById(R.id.viewPager);
    
        //Important!!! Do not fire the existing adapter!!
        if (viewPagerAdapter == null) {
            viewPagerAdapter = new ViewPagerAdapter(getChildFragmentManager());
            viewPagerAdapter.addFragments(new AFragment(), "A");
            viewPagerAdapter.addFragments(new BFragment(), "B");
            viewPagerAdapter.addFragments(new CFragment(), "C");
        }
        //Allocate retention buffers for three tabs, mandatory
        viewPager.setOffscreenPageLimit(3);
        tabLayout.setupWithViewPager(viewPager);
        viewPager.setAdapter(viewPagerAdapter);
    
        return view;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多