【问题标题】:FragmentStatePagerAdapter returns null viewsFragmentStatePagerAdapter 返回空视图
【发布时间】:2014-05-12 08:38:07
【问题描述】:

我使用FragmentStatePagerAdapter 来在 ViewPager 中显示片段,所有这些片段都遵循相同的布局容器(FrameLayout),但它的数量在运行时是可变的,所以我把所有它们中的一个静态List片段并将该列表传递给FragmentStatePagerAdapter(第一次通过它的构造函数,之后每次我只更新列表和notifydatasetchanged):

public class MyPageAdapter extends FragmentStatePagerAdapter {

    public static List<Fragment> myFragments = new ArrayList<Fragment>();
    public MyPageAdapter(FragmentManager fragmentManager, List<Fragment> fragments) {
        super(fragmentManager);

        myFragments = fragments;

    }

    public Fragment getItem(int i) {

        return myFragments.get(i);

    }

    @Override
    public int getCount() {

         return myFragments.size();

    }

}

现在这是我在运行时创建Fragment List 的方式:

public List<Fragment> fragmenting(int num) { // num: the Number of fragments i wanna create 

        List<Fragment> fragments = new Vector<Fragment>();

        for(int i =0; i < num ; i++){
            Bundle page = new Bundle();
            page.putInt("index", i);
            fragments.add(Fragment.instantiate(mContext, MyFragment.class.getName(), page));
        }

        return fragments;

}

提交新的片段ViewPager

public static PagerAdapter ad;
public static ViewPager sViewPager;
private static MyPageAdapter mpa;

public void display_fragments(int i, boolean init) {

    if(init){ // init means we are in the first initialization and it goes here only at the first time
        List<Fragment> fragments = fragmenting(i);
        mpa = new MyPageAdapter(getChildFragmentManager(), fragments);
        sViewPager = (ViewPager) view.findViewById(R.id.my_view_pager);
    }else{ // is our case here
        List<Fragment> fragments = fragmenting(i);
        MyPageAdapter.myFragments = fragments;
        mpa.notifyDataSetChanged();
    }

    ad = mpa;
    sViewPager.setAdapter(ad);
    sViewPager.setCurrentItem(0);

}

在这个阶段一切正常,如果我浏览指定数量的片段,它将有效地导航,每个片段都有MyFragment片段的容器。

但是当尝试访问片段的视图时,它仅根据前两个片段中的MyFragment返回指定的视图(FrameLayout),然后返回null ,我尝试通过循环mpa 打印出返回的视图:

for(int g =0; g < mpa.getCount(); g++){
    System.out.println(mpa.getItem(g));
}

这就是我得到的:

05-12 08:36:10.175: I/System.out(1062): MyFragment{53535b8c #1 id=0x7f06005e}
05-12 08:36:10.175: I/System.out(1062): MyFragment{540e71b4 #0 id=0x7f06005e}
05-12 08:36:10.175: I/System.out(1062): MyFragment{540e7298}
05-12 08:36:10.175: I/System.out(1062): MyFragment{540e737c}
05-12 08:36:10.175: I/System.out(1062): MyFragment{540e7460}

【问题讨论】:

  • 您尝试打印时在哪一页?如果片段不是ViewPager 中的当前可见页面(或可见页面左侧和右侧的页面),则片段的视图将被销毁。
  • @Luksprog 我在第一页,它包含所有其他片段
  • 那么这是正常的,正如我上面所说的。适配器的构建是高效的,因此它会破坏用户无法立即访问的片段视图。你需要重新思考你的逻辑,你也做错了其他事情。
  • @Luksprog 根据您的信息,添加 sViewPager.setCurrentItem(g); 时它必须工作,但它的行为也相同,以及您正在处理的其他事情是什么。您可以将所有这些都提供到答案中

标签: android android-fragments fragmentstatepageradapter


【解决方案1】:

根据MyFragment中的MyFragment返回指定的View(FrameLayout) 仅前两个片段,之后返回 null

适配器的构建是高效的,因此它会破坏无法立即访问的片段的视图(可访问的片段将是当前可见的每侧一加一(便于滑动),除非你用过setOffscreenPageLimit())。在您的情况下,如果您在当前页面为0 时调用for 循环,您将获得仅页面01 的有效片段视图。调用setCurrentItem() 不起作用,因为转换不会立即发生(因此其他片段不会立即构建)。

我不知道你想对片段的视图做什么,但你需要重新考虑你的方法。无论如何,您不应该像现在一样尝试更新它们,您应该立即更新用户可用的片段(我上面提到的片段)。更新其他片段的视图没有意义,因为用户可能根本不使用它们,这将是一种浪费。

您在代码中做错了其他事情,例如:

基于片段列表的适配器肯定会失败,因为您将丢失片段的正确引用。适配器不会每次都调用getItem() 方法,在某些情况下,它会自行重新创建片段,使您的列表片段引用无效(尤其是当您将片段列表声明为静态时)。如果您要使用列表,请确保按顺序保留对片段的引用(例如,您可以获得对适配器的 instantiateItem() 方法中使用的实际片段的引用)。

不要像你做的那样让每个类字段都是静态的。您不应该将视图字段声明为静态,因为它们包含对 Context 的引用,并且您可能会泄露它。片段列表不应设为静态,因为使用适配器的片段可能会重新创建,在这种情况下,适配器本身将被重新创建,但您的列表将保存旧内容。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-10-03
    • 2011-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 2017-05-22
    相关资源
    最近更新 更多