一、FragmentPagerAdapter 和 FragmentPagerStateAdapter
1. 区别
setOffScreenPageLimit(int limit)
设置viewpager左右预加载页,
FragmentPagerAdapter将每一个生成的Fragment保存在内存中,limit外的Fragment一旦初始化后就不销毁。
FragmentStatePagerAdapter对limit外的Fragment销毁。
使用场景:
对于固定较少数量的页面使用FragmentPagerAdapter,如引导页,Tab页面;
对于拥有大量页面的情况应使用FragmentStatePagerAdapter避免占用大量内存,如图片预览
2. Fragment引用
不应该在Activity的成员变量中实例化 Fragment 或实例化 List<Fragment> 去存储 Fragment。原因涉及到Fragment的保存与恢复,下面会分析。
如果需要获取到 Fragment,则需要使用如下结构:
public class MyPagerAdapter extends FragmentStatePagerAdapter {
SparseArray<Fragment> registeredFragments = new SparseArray<Fragment>();
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public int getCount() {
return ...;
}
@Override
public Fragment getItem(int position) {
return MyFragment.newInstance(...);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
registeredFragments.put(position, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
registeredFragments.remove(position);
super.destroyItem(container, position, object);
}
public Fragment getRegisteredFragment(int position) {
return registeredFragments.get(position);
}
}
二、Fragment 状态保存与恢复
Fragmentde 的保存与恢复涉及到 FragmentManagerImpl中的两个方法 saveAllState和restoreAllState。
当Activity触发onSaveInstanceState时,会将 Fragmentmanager的mAdded、mActive数组中的Fragment转化成FragmentState,而FragmentState是一个Parcel,可以被存到Activity的Bundle中,等到Activity再次onCreate时,会将已保存在Bundle中的FragmentState再恢复出来,转化成FragmentManager的mAdded,mActive。
FragmentManager帮我们做了所有的保存与恢复的工作,如果我们在Activity中重新创建Fragment,那么这些在Activity中创建的Fragment可能并不是FragmentManager的Fragment。
下面写个例子
public class DemoActivity extends FragmentActivity {
private List<Fragment> fragments = new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
fragments.add(DemoFragment.newInstance(0));
fragments.add(DemoFragment.newInstance(1));
fragments.add(DemoFragment.newInstance(2));
final Adapter adapter = new Adapter(fragments, fm);
vp.setAdapter(adapter);
vp.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
...
@Override
public void onPageSelected(int i) {
Log.d(TAG, String.valueOf(adapter.array.get(i) == adapter.fragments.get(i)));
}
});
}
}
static class Adapter extends FragmentPagerAdapter {
Adapter(List<Fragment> fragments, FragmentManager fm) {
super(fm);
this.fragments = fragments;
}
List<Fragment> fragments;
SparseArray<Fragment> array = new SparseArray<>();
@NonNull
@Override
public Object instantiateItem(@NonNull ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
array.put(position, fragment);
return fragment;
}
@Override
public Fragment getItem(int i) {
return fragments.get(i);
}
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
array.delete(position);
super.destroyItem(container, position, object);
}
@Override
public int getCount() {
return 3;
}
}
上面的代码在Adapter中 保存了两个关于Fragment的集合,其中fragment是Activity创建的,array存的是每次PagerAdapter执行instantiateItem创建的Fragment。
需要验证的是,当Activity被重建的时候(通过开发者选项不保留活动),两个Fragment集合是一样的吗?答案在 onPageSelected中。
当每次在滑动的时候,onPageSelected 中的 Log 打印的是什么呢?答案是 false。
网友评论