项目需求,如下图
实现方法
主MainActivity 承载5个fragment,对应着下面5个按钮进行切换,该处使用的fragment的add与hide方法同时加载,调用方法如下:
private void showFragment(Fragment targetFragment) {
//如果当前fragment和目标fragment一致
if (targetFragment == currentFragment) {
return;
}
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
if (currentFragment != null) {
ft.hide(currentFragment);
}
if (targetFragment.isAdded()) {
//如果目标已被添加,直接显示即可
ft.show(targetFragment);
} else {
//如果未被添加,则需添加后显示
ft.add(R.id.framelayout, targetFragment).show(targetFragment);
}
ft.commitAllowingStateLoss();
currentFragment = targetFragment;
}
而首页界面对应的是多个不同tab,用ViewPager 承载fragment进行实现,开始的时候使用原始FragmentPagerAdapter,只重写了
@Override
public Fragment getItem(int i) {
return mFragmentList.get(i);
}
@Override
public int getCount() {
return mFragmentList == null ? 0 : mFragmentList.size();
}
并在首页fragment创建的时候调用
mHomePagerAdapter = new FragmentAdapter(getChildFragmentManager(), mFragmentList);
viewPager.setAdapter(mHomePagerAdapter);
viewPager.setCurrentItem(0);
magicIndicator.onPageSelected(0);
收到数据回调的时候,重新如下处理:
@Override
public void getUserTypesSuccess(List list) {
mTemplateTypeModels = list;
Collections.sort(mTemplateTypeModels, (o1, o2) -> o1.getTypeOrder() - o2.getTypeOrder());
mCommonNavigatorAdapter.notifyDataSetChanged();
if (mFragmentList == null) mFragmentList = new ArrayList<>();
mFragmentList.clear();
for (TemplateTypeModel model : list) {
mFragmentList.add(TypeListFragment.newInstance(model));
}
mHomePagerAdapter.notifyDataSetChanged();
}
问题
界面未收到刷新(这里有个注意点,在fragment里承载viewpager要使用getChildFragmentManager)
修改方式:
怀疑为缓存问题,实际也正是viewpager缓存问题
尝试拿到数据,重新设置adapter
@Override
public void getUserTypesSuccess(List list) {
mTemplateTypeModels = list;
Collections.sort(mTemplateTypeModels, (o1, o2) -> o1.getTypeOrder() - o2.getTypeOrder());
mCommonNavigatorAdapter.notifyDataSetChanged();
if (mFragmentList == null) mFragmentList = new ArrayList<>();
mFragmentList.clear();
for (TemplateTypeModel model : list) {
mFragmentList.add(TypeListFragment.newInstance(model));
}
mHomePagerAdapter = new FragmentAdapter(getChildFragmentManager(), mFragmentList);
viewPager.setAdapter(mHomePagerAdapter);
viewPager.setCurrentItem(0);
magicIndicator.onPageSelected(0);
}
问题
运行发现更新的时候,可以正常更新数据,等等,增删list 数量的时候,发现viewpager中fragment 展示的界面和实际期望的界面不一样,莫非还是缓存问题,上网经过一番,需要设置adapter 中
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}
修改
加入之后,发现效果不明显,继续百度,有人说要删除fragmentmanager中的fragment,好吧,加入,看一下,继续修改
@Override
public void getUserTypesSuccess(List list) {
List olds = getChildFragmentManager().getFragments();
if (olds != null) {
FragmentTransaction ft = getChildFragmentManager().beginTransaction();//获得FragmentTransaction 事务
for (Fragment f : olds) {
ft.remove(f); //遍历删除fragment
}
ft.commit();
getChildFragmentManager().executePendingTransactions();
}
mTemplateTypeModels = list;
Collections.sort(mTemplateTypeModels, (o1, o2) -> o1.getTypeOrder() - o2.getTypeOrder());
mCommonNavigatorAdapter.notifyDataSetChanged();
if (mFragmentList == null) mFragmentList = new ArrayList<>();
mFragmentList.clear();
for (TemplateTypeModel model : list) {
mFragmentList.add(TypeListFragment.newInstance(model));
}
mHomePagerAdapter = new FragmentAdapter(getChildFragmentManager(), mFragmentList);
viewPager.setAdapter(mHomePagerAdapter);
viewPager.setCurrentItem(0);
magicIndicator.onPageSelected(0);
}
运行,完美解决问题,不过总感觉不够优雅
使用FragmentStatePagerAdapter
由于FragmentPagerAdapter和FragmentStatePagerAdapter内部缓存机制不一样,FragmentStatePagerAdapter是直接销毁fragment,而不是复用,具体区别可以参考 FragmentPagerAdapter与FragmentStatePagerAdapter区别
viewPager.setAdapter(mHomePagerAdapter = new FragmentStatePagerAdapter(getChildFragmentManager()) {
@Override
public int getCount() {
return mFragmentList == null ? 0 : mFragmentList.size();
}
@Override
public Fragment getItem(int i) {
return mFragmentList.get(i);
}
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}
});
这里可以直接使用notifyDataSetChanged进行界面的刷新
@Override
public void getUserTypesSuccess(List list) {
mTemplateTypeModels = list;
Collections.sort(mTemplateTypeModels, (o1, o2) -> o1.getTypeOrder() - o2.getTypeOrder());
mCommonNavigatorAdapter.notifyDataSetChanged();
if (mFragmentList == null) mFragmentList = new ArrayList<>();
mFragmentList.clear();
for (TemplateTypeModel model : list) {
mFragmentList.add(TypeListFragment.newInstance(model));
}
mHomePagerAdapter.notifyDataSetChanged();
viewPager.setCurrentItem(0);
magicIndicator.onPageSelected(0);
}
总结:
遇到viewpager 使用fragment,界面不刷新的问题,可以考虑使用FragmentStatePagerAdapter,并重写
@Override
public int getItemPosition(@NonNull Object object) {
return POSITION_NONE;
}
然后就和使用listview等数据刷新行为一致了