您的位置:首页 > 编程语言 > PHP开发

Fragment与FragmentPagerAdapter的使用

2015-12-14 16:51 549 查看

Fragment与FragmentPagerAdapter的使用

我也是一名刚刚参加工作四个月的小程序猿,写博客只是为了分享一下博主在工作中遇到的一些困难以及难点,如果有什么说错了或者不足的地方,欢迎前辈们指出。

博主是做盲人应用的,因为ListView对盲人比较不和谐把。。所以公司一般要程序猿用TabHost内放ViewPager的方式来实现需要的效果。

前两天公司要求做一个咨询2.0的项目,布局风格是外层TabHost,下面有三个Tab,每个Tab对应的是一个FragmentActivity。
博主在写的过程中也遇到了一些困难,现在拿出来跟大家讨论交流下,下面进入正题。


说到Fragment与ViewPager的联合使用就必须得学会联系这两者的Adapter

Fragment的Adapter有两种。一种是FragmentPagerAdapter,另一种是FragmentStatePagerAdapter。从Google官网我们能了解到FragmentPagerAdapter是PagerAdapter中的其中一种实现。它将每一个页面表示为一个 Fragment,并且每一个Fragment都将会保存到fragment manager当中。而且,当用户没可能再次回到页面的时候,fragment manager才会将这个Fragment销毁。那么这样的话,问题就出来了。FragmentPagerAdapter只适合静态的Fragment,因为当该界面不可见时view hierarchy将会被销毁。这样的话会应用程序占用太多资源,所以当页面数量较多时,推荐使用FragmentStatePagerAdapter。

看完Adapter的说明之后,再来说一下博主在工作之中遇到的问题,博主做的是一个资源APP,在另一个界面点击添加后,跳回前一界面时,要同步显示用户订阅的资料。说到这,相信大家也都清楚问题出在哪里了。

问题出在内容刷新这里。首先我们来总结一下问题发生的原因:从官网的文档我们可以得知,FragmentPagerAdapter是会对Fragment做出缓存的。当我们从第二个界面跳回第一个界面时,Activity会执行onResume的方法,而此时我们在Activity的onResume方法中重新加载Fragment并对Adapter进行刷新时,并不会刷新Fragment,而是会去调用FragmentManager中保存的Fragment。

知道问题发生的原因了之后博主在网上看了很多博客,也自己做了一些试验,最后得出了两种可行的方法。

方法1:我们在Adapter中写一个设置Adapter中数据源的方法,并在这个方法中,移除所有FragmentManager中缓存的Fragment,注意此时的提交方法必须使用commitAllowingStateLoss(),如果使用普通的commit()的话可能会报出java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState 这个错误,出现这个问题的原因是因为在当Activity变的”容易”被销毁时,系统会自动调用onSaveInstanceState方法。

public void setFragments(ArrayList<Fragment> fragments) {
if (this.list != null) {
FragmentTransaction ft = fm.beginTransaction();
for (Fragment f : this.list) {
ft.remove(f);
}
ft.commitAllowingStateLoss();
ft = null;
fm.executePendingTransactions();
}
this.list = fragments;
notifyDataSetChanged();
}


方法2:复写父类的instantiateItem的方法。该方法返回的是container所对应的一个Key。

在复写了该方法之后我们首先拿到他缓存中的Fragment,然后在拿到Fragmetn所对应·的Tag。然后我们根据fragmentsUpdateFlag数组中的boolean值来判断该Fragment是否需要更新,如果需要更新则移除掉原来的Fragment并把新的Fragment添加进去。

boolean[] fragmentsUpdateFlag = new boolean[list.size()];
@Override
public Object instantiateItem(ViewGroup container, int position) {
//得到缓存的fragment
Fragment fragment = (Fragment) super.instantiateItem(container,
position);
//得到tag,这点很重要
String fragmentTag = fragment.getTag();
if (fragmentsUpdateFlag[position % fragmentsUpdateFlag.length]) {
//如果这个fragment需要更新
FragmentTransaction ft = fm.beginTransaction();
//移除旧的fragment
ft.remove(fragment);
//换成 新的fragment
fragment = list.get(position % list.size());
//添加新fragment时必须用前面获得的tag,这点很重要
ft.add(container.getId(), fragment, fragmentTag);
ft.attach(fragment);
ft.commit();
//复位更新标志
fragmentsUpdateFlag[position % fragmentsUpdateFlag.length] = false;
}
return fragment;
}


上面两种方法,第一种是直接粗暴的移除了缓存中所有的Fragment,第二种方法则是根据需要来选择移除,所以一般来说推荐使用第二种方法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  viewpager