近期在做一个类似于问卷调查答题的一个项目,涉及到Viewpager+Frament的使用,需要使用ViewPager中的Fragement去显示每一道题目,并且可以实现点击上一题和下一题的操作,与一般使用不一样的地方是,每套问卷的题目数量不一样,下一题的跳转是根据当前题的选项去决定,所以Frament的界面数量不能确定,无法事先存放。后来我就采用了进行动态添加Fragment和动态删除Fragment的方式去处理这样的需求,当然之后就遇到很多问题了。。
一开始我想法很简单就是把viewpager当成一般的adapter来做,添加和删除,直接用list的add和remove来操作,之后在adapter.notifyDataSetChanged去更新adapter,结果发现删除没啥问题,但是删除后在添加后,奇怪的是再添加的界面上的数据与之前删除的界面上的数据一样。。而且我调用界面上的控件就会出空指针异常。我第一直觉告诉我是,我没有删除那个界面添加只是调用了原先的那个界面,我就想会不会是viewpager的缓存问题。
之后就开始找网上的资料,搜索关于viewpager的缓存的问题。然后我找到关于viewPager.setOffscreenPageLimit(num);// 设置缓存页面,当前页面的相邻N各页面都会被缓存 ,这个方法setOffscreenPageLimit(num),几经测试过后发现并没有我想要那个效果,就算我设置为0删除添加后也还是会有界面缓存的,结果发现这个方法是用作与预加载时用的,当前如果有5个界面,我设置setOffscreenPageLimit为2当我显示第一个界面的时候,其实我已经在加载了第二第三个界面,但我问题不是预加载出现的问题,就算我不预加载,将值设置为0,那结果就是每切换一个界面就执行当前自己的生命周期,但是其实我那个被删除的界面一直缓存着,这种方式只是重新走了下他的生命周期而已,并没有创建新的Fragment。
然后我开始从notifyDataSetChanged这里去找问题,感谢下这位同学分享的http://blog.csdn.net/u013034750/article/details/24323123 也是这篇文章让知道了原来是FragmentManager缓存了界面,必须在instantiateItem()中用FragmentTransaction去remove这个Fragment。
最后通过这篇文章http://blog.csdn.net/z13759561330/article/details/40737381 完美的解决了我的问题,每次在调用instantiateItem的时候我去判断是否最后一个标签页,是否是再次添加的界面,是否已经删除过的界面,达成这些判断的时候我将最后那个界面的Fragment进行替换成list中最后一项的界面。我就直接上代码看啦。。
private class MyPagerFragmentAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
private FragmentManager fm;
public MyPagerFragmentAdapter(FragmentManager fm,
List<Fragment> fragments) {
super(fm);
this.fm = fm;
this.fragments = fragments;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Log.i("TAG", "destroyItem___________");
super.destroyItem(container, position, object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Log.i("TAG", "instantiateItem___________");
// 得到缓存的fragment
Fragment fragment = (Fragment) super.instantiateItem(container,
position);
// 得到tag,这点很重要
String fragmentTag = fragment.getTag();
Log.i("TAG", "替换___________1");
if (position == (fragmentList.size() - 1)) {// 是否为最后一页(因为会根据setOffscreenPageLimit的数量执行相应次数)
if (isDelete) {// 是否被删除过,删除事件中修改为True
if (isAdd) {// 是否点击了添加,添加事件中修改为True
Log.i("TAG", "替换___________2");
// 如果这个fragment需要更新
FragmentTransaction ft = fm.beginTransaction();
// 移除旧的fragment
ft.remove(fragment);
// 换成新的fragment
fragment = fragments.get(fragmentList.size() - 1);
// 添加新fragment时必须用前面获得的tag,这点很重要
ft.add(container.getId(), fragment, fragmentTag);
ft.attach(fragment);
ft.commit();
isAdd = false;
isDelete = false;
}
}
}
return fragment;
}
@Override
public int getItemPosition(Object object) {
Log.i("TAG", "getItemPosition___________");
return POSITION_NONE;
}
@Override
public Fragment getItem(int arg0) {
Log.i("TAG", "getitem___________");
return fragments.get(arg0);
}
@Override
public int getCount() {
Log.i("TAG", "getCount___________");
return fragments.size();
}
}
总结:以上是我对Viewpager+Fragment的使用以及遇到的问题的总结,可能不完善,或不专业,望看到此贴的大牛指点,谢谢!