导航回FragmentPagerAdapter - >碎片是空的

时间:2013-07-16 09:27:23

标签: android android-fragments android-viewpager fragmentpageradapter back-stack

我有一个片段(我称之为pagerFragment),它被添加到后台并且可见。它包含viewPagerFragmentPagerAdapterFragmentPagerAdapter拥有(比方说)两个片段:A和B.

首先添加片段效果很好。

片段A有一个按钮,一旦点击,就会在后台堆叠中添加一个片段(C)。

问题是:如果我添加该片段(C),然后单击返回,pagerAdapter为空,我看不到任何片段。

如果我使用hack,并在pagerFragment s onDestroyView()中销毁子片段(A和B),这就解决了问题,尽管我不想使用这个hack

任何想法可能是什么问题?

5 个答案:

答案 0 :(得分:83)

我遇到了同样的问题。对我来说解决方案很简单:

在onCreateView中我有:

// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getActivity()
    .getSupportFragmentManager());

其中SectionPageAdapter是这样的:

class SectionsPagerAdapter extends FragmentPagerAdapter {
...
}
将getSupportFragmentManager更改为

mSectionsPagerAdapter = new SectionsPagerAdapter(getChildFragmentManager());
它开始工作了! 希望这会有所帮助。

答案 1 :(得分:13)

听起来您正在使用嵌套片段,因为您的ViewPager在PagerFragment中。您是否已将getChildFragmentManager()传递给FragmentPagerAdapter的构造函数?如果没有,你应该。

我认为你不需要FragmentStatePagerAdapter,但我会给它一个镜头,因为它处理保存和恢复Fragment状态。你的onDestroyView()hack工作的事实让我觉得你可能想要一个FragmentStatePagerAdapter。

它也可能与FragmentPagerAdapter添加片段的方式有关。 FragmentPagerAdapter不会将片段添加到Backstack。想象一下,如果您的ViewPager中添加了10多个页面,并且用户可以浏览它们。用户需要回击11次才能退出应用程序。

它也可能与这篇文章有关:Nested Fragments and The Back Stack

此外,我不确定你要将片段C添加到。您是否将其添加到与ViewPager相同的容器中?

至少你有几个选择可以调查。在这些情况下,我喜欢调试Android SDK源代码,看看是什么导致了这种行为。我建议抓取AOSP source并添加框架/支持和框架/ base作为SDK源。这是理解正在发生的事情的唯一真实方式,并避免在事情发生之前进行随机更改。

答案 2 :(得分:1)

我刚刚在项目中遇到了问题。根本原因是FragmentPagerAdapter的工作方式:

FragmentPagerAdapter只是从它的View中分离出一个他当前不需要的片段,但是不会从FragmentManager中删除它。当他想再次显示片段时,他会查看FragmentManager是否仍然包含使用从ViewPager的视图ID创建的标记和由适配器getItemId(position)调用返回的id的片段。如果他找到一个Fragment,他只是在FragmentManager的更新事务中安排Fragment附加到它的View。只有当他没有以这种方式找到片段时,他才使用适配器getItem(position)调用创建一个新片段!

包含带有FragmentPagerAdapter的ViewPager的Fragment的问题是,当包含Fragment放入后端堆栈时,FragmentManager的内容永远不会被清除。如果包含Fragment从后向堆栈返回,则会创建一个新视图,但FragmentManager仍然包含附加到旧视图的片段,并且现有片段的附加不再起作用。

解决此问题的最简单方法是避免嵌套片段。 :)

第二种最简单的方法就像在其他帖子中已经提到的那样,使用ChildFragmentManager作为FragmentPagerAdapter,因为这个在容器片段的生命周期中得到了适当的更新。

由于有两个选项都不可能的项目(作为我当前的项目),我在这里发布了一个解决方案,通过使用子片段的hashCode作为该位置片段的项目ID,可以使用任意FragmentManager 。它的代价是存储适配器中所有位置的所有片段。

public class MyPagerAdapter extends FragmentPagerAdapter {

private static int COUNT = ...;
private final FragmentManager fragmentManager;
private Fragment[] subFragments = new Fragment[COUNT];
private FragmentTransaction cleanupTransaction;

public MyPagerAdapter(FragmentManager fragmentManager) {
    super(fragmentManager);
    this.fragmentManager = fragmentManager;
}

@Override
public Fragment getItem(int position) {
    return getSubFragmentAtPosition(position);
}

@Override
public int getCount() {
    return COUNT;
}

@Override
public long getItemId(int position) {
    return getSubFragmentAtPosition(position).hashCode();
}

//The next three methods are needed to remove fragments no longer used from the fragment manager
@Override
public void startUpdate(ViewGroup container) {
    super.startUpdate(container);
    cleanupTransaction = fragmentManager.beginTransaction();
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    super.destroyItem(container, position, object);
    cleanupTransaction.remove((Fragment) object);
}

@Override
public void finishUpdate(ViewGroup container) {
    super.finishUpdate(container);
    cleanupTransaction.commit();
}

private Fragment getSubFragmentAtPosition(int position){
    if (subFragments[position] == null){
        subFragments[position] = ...;
    }
    return subFragments[position];
}

}

答案 3 :(得分:0)

使用getChildFragmentManager()代替getSupportFragmentManager()。 它会工作正常。

答案 4 :(得分:0)

我遇到了同样的问题,只需一次设置适配器两次即可。

示例代码:

private fun displayImg(photo1:String, photo2:String){
    val pager:ViewPager = v?.findViewById(R.id.ProductImgPager)!!
    val arr = ArrayList<String>()
    arr.add(photo1)
    arr.add(photo2)
    pager.adapter = AdapterImageView(fm, arr ,arr.size)
    pager.adapter = AdapterImageView(fm, arr ,arr.size)

}