FragmentPagerAdapter的getItem方法未被触发。

38

目前,使用 FragmentActivity,我使用以下代码在两种类型的片段之间进行切换。

private void toggle() {
    Fragment oldFragment = getSupportFragmentManager().findFragmentById(R.id.content);
    Fragment fragment = null;
    if (oldFragment instanceof ColorFragment) {
        fragment = new ViewPagerFragment();
    } else {
        fragment = new ColorFragment(android.R.color.black);
    }

    getSupportFragmentManager().beginTransaction().replace(R.id.content, fragment).commitAllowingStateLoss();
}

正在切换2个片段。

  • ColorFragment - 一个简单的片段,其背景填充为纯黑色。
  • ViewPagerFragment - 一个包含ViewPager的片段。用户可以在紫色和蓝色的颜色片段之间滑动。

负责切换紫色和蓝色颜色片段的代码如下所示。

private static class MyFragmentPagerAdapter extends FragmentPagerAdapter {

    public MyFragmentPagerAdapter(FragmentManager fm) {
        super(fm);
    }

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

    @Override
    public Fragment getItem(int position) {
        switch (position) {
        case 0:
            return new ColorFragment(android.R.color.holo_purple);
        default:
            return new ColorFragment(android.R.color.holo_blue_bright);
        }
    }      
} 

然而,在切换过程中我遇到了奇怪的行为。

  1. 黑色片段被显示。
  2. 切换。
  3. 可以在紫色和蓝色片段之间滑动的视图分页器显示出来了。
  4. 切换。
  5. 黑色片段被显示。
  6. 切换。
  7. 什么都没有显示,因为MyFragmentPagerAdapter的getItem未被触发。

我认为我的情况类似于FragmentPagerAdapter getItem is not called

然而,由于在页面切换时可能会有更多的开销成本,我不想使用FragmentStatePagerAdapter

有什么解决此问题的方法吗?

我包括了一个完整可运行的源代码以演示这个问题:https://www.dropbox.com/s/jok9tz5ktvfcteo/viewpagerbug.zip


我更倾向于不使用FragmentStatePagerAdapter - 那么,你至少试过它以查看它是否有任何差异吗?由于在页面之间切换时可能会产生更多的开销成本。- 什么潜在的开销成本?你发布的包含两个片段的方案非常简单。 - user
@Luksprog 两个紫色和蓝色的片段仅用于演示目的。实际情况下,片段更加复杂。我知道通过保存信息通过bundle或保留实例片段技术可以减少某些开销。然而,我意识到避免使用FragmentStatePagerAdapter是避免开销的最佳方法。 - Cheok Yan Cheng
5个回答

113

有什么解决此问题的方法吗?

我已经下载了你的代码,问题出在你没有正确处理那些Fragments。更准确地说,你在基于ViewPagerFragment中使用了嵌套的Fragments,并且你为该ViewPager创建了以下适配器:

MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(this.getFragmentManager());

相反,您应该使用 getChildFragmentManager() 来绑定嵌套片段:

MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(this.getChildFragmentManager());

另外,您不应该通过构造函数传递数据到 Fragment ,因为这些数据将无法在配置更改后保留,会出现问题。 可以使用一个 Bundle 来代替。


1
嗨,非常感谢您的大力帮助。但是,我不明白为什么使用this.getChildFragmentManager会解决问题。根据http://developer.android.com/reference/android/support/v4/app/FragmentPagerAdapter.html,它通过getSupportFragmentManager()使用FragmentActivity的片段管理器(FragmentActivity是ViewPager的所有者)。它不使用ArrayListFragment的片段管理器(ArrayListFragment(s)是ViewPager的可滑动内容)。 - Cheok Yan Cheng
1
我不确定这是否真正回答了我的问题。我认为所给的示例是在活动中的片段。使用getFragmentManager是有意义的。但是,如果是嵌套在片段中的子片段,则需要使用getChildFragmentManager。这在某种程度上是Google发布的“规则”:http://developer.android.com/about/versions/android-4.2.html#NestedFragments - Cheok Yan Cheng
12
在你的 ViewPagerFragment 示例中,getFragmentManager() 将返回来自 ActivityFragmentManager(基本上是使用 FragmentActivity 添加 FragmentgetSupportFragmentmanager() 的值)。由于您使用了嵌套片段,因此这些片段需要使用 getChildFragmentManager() 以便将其附加到父片段。在 Fragment 中,getFragmentManager()getChildFragmentManager() 不是 同一件事(一个返回与该片段相关的片段,而另一个则是用于其嵌套片段的片段管理器)。 - user
2
如果我可以 +1 多次,我一定会这么做!非常感谢您的答案和解释! - Matthew Clark
完美运行!我使用FragmentStatePagerAdapter时也遇到了同样的问题。 - dy_
显示剩余5条评论

12

全球测试通过的解决方案。

getSupportFragmentManager() 有时会保留空引用,而 View pager 不会创建新的 fragment 实例,因为它找到了对同一 fragment 的引用。所以为了克服这个问题,在代码中使用 getChildFragmentManager() 可以简单地解决问题。

不要这样做

new PagerAdapter(getSupportFragmentManager(), fragments);

要这样做

new PagerAdapter(getChildFragmentManager() , fragments);


2

使用FragmentStatePagerAdapter代替FragmentPagerAdapter

或者

你可以使用new MyFragmentPagerAdapter(this.getChildFragmentManager())

希望对你有所帮助 :)


1
在我的情况下,我正确地调用了。
MyFragmentPagerAdapter myFragmentPagerAdapter = new MyFragmentPagerAdapter(this.getChildFragmentManager());

但是在嵌套的片段中,我试图使用以下方式将容器片段替换为另一个片段:
getFragmentManager()

你需要前往该活动并调用它

getActivity().getSupportFragmentManager();

0
在我的情况下,将以下内容添加到我的FragmentPagerAdapter后它可以工作:
    @Override
    public int getItemPosition(Object object) {
        return POSITION_NONE;
    }

我也像Luksprog说的那样使用了getChildFragmentManager()


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接