相信在android开发中,使用ViewPage是必须的,而和ViewPage配合使用的那就属Fragment最为常见了,还有就是ImageView。
今天所说的是Fragment在ViewPage中的使用,通常我们所使用的适配器是FragmentPagerAdapter。一般情况下,我们在ViewPage中添加的碎片(Fragment)是固定的,不会发生变更的,那么在FragmentPagerAdapter适配器中重写的几个方法就是固定的,不需要重写其他的方法,这里我就不再赘述了。
可是如果ViewPage中的碎片在某种情况下出现替换,该如何处理呐?
通常的思路就是: 使用 FragmentPagerAdapter 将所有的碎片添加到ViewPage中,如果在某个条件的触发下,更改Fragment的数据源,然后再通过notifyDataSetChanged()的方法,通知适配器更新数据,可是如果这样运行的话,发现其中该被替换掉的碎片没有被替换掉,还是会出现原先的碎片,不管你如何清理ViewPage中的控件、如何更改数据源,碎片始终还是不会被替换。
那我们就会想,代码没问题呀!逻辑没错呀!为什么就是不被替换呐????
我认为这个主要是缓存的问题,我们第一次添加到ViewPage中的碎片被放到了缓存中了,等我们需要替换其中某个碎片时,只是更改了数据源,而在缓存中的还是之前的碎片,所以不管你怎么切换都不会把碎片替换掉。
其实解决的方法有三种:
一、继续使用FragmentPagerAdapter ,重写 instantiateItem(ViewGroup container, int position) 方法。
贴上适配器中的代码如下:
public class MyAdapter extends FragmentPagerAdapter {
protected List<Fragment> fragmentsList; //数据源
private boolean[] flags; //标记碎片的
private FragmentManager fm;
public MyAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fm = fm;
this.fragmentsList = fragments;
flags = new boolean[fragmentsList.size()];
}
//提供一个公共方法,供其他类调用,刷新适配器
public void refresh(int... indexs) {
for (int i = 0; i < indexs.length; i++) {
flags[indexs[i]] = true;
}
notifyDataSetChanged();
}
/**
* POSITION_NONE;//返回这个表示该对象已改变,需要刷新
* POSITION_UNCHANGED;//反之不刷新
*/
@Override
public int getItemPosition(Object object) {
// TODO Auto-generated method stub
return PagerAdapter.POSITION_NONE;
}
//这个方法是重点,只有重写了这个方法才会实现碎片的替换。
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
// 得到Tag
String fragmentTag = fragment.getTag();
if (flags[position % flags.length] && fragment != fragmentsList.get(position % fragmentsList.size())) {
// 如果这个Fragment需要更新
FragmentTransaction ft = fm.beginTransaction();
// 移除旧的Fragment
ft.remove(fragment);
// 换成新的Frgment
fragment = fragmentsList.get(position % fragmentsList.size());
// 用之前的Tab添加新的Frgament
ft.add(container.getId(), fragment, fragmentTag);
ft.attach(fragment);
ft.commitAllowingStateLoss();
// 复位更新标志
flags[position % flags.length] = false;
}
return fragment;
}
@Override
public int getCount() {
return fragmentsList.size();
}
@Override
public Fragment getItem(int arg0) {
return fragmentsList.get(arg0);
}
}
二、使用FragmentStatePagerAdapter适配器,也许重写instantiateItem(ViewGroup container, int position) 。
代码如下:
public class ViewPageAdapter extends FragmentStatePagerAdapter {
private List<Fragment> mDataList;
public ViewPageAdapter(FragmentManager fm, List<Fragment> list) {
super(fm);
mDataList = list;
}
@Override
public Fragment getItem(int position) {
return mDataList.get(position);
}
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
@Override
public int getCount() {
return mDataList.size();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
final Object fragment = super.instantiateItem(container, position);
try {
final Field saveFragmentStateField = Fragment.class.getDeclaredField("mSavedFragmentState");
saveFragmentStateField.setAccessible(true);
final Bundle savedFragmentState = (Bundle) saveFragmentStateField.get(fragment);
if (savedFragmentState != null) {
savedFragmentState.setClassLoader(Fragment.class.getClassLoader());
}
} catch (Exception e) {
e.printStackTrace();
}
return fragment;
}
}
三、使用Fragment的管理器FragmentManager来对Fragment进行替换。
具体方法点击此链接
以上三种方法是我对Fragment的替换所采取的方法,如若有更好的方法或有不足之处,望指出!谢谢!