Fragment 注意事项

一、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,则需要使用如下结构:

public class MyPagerAdapter extends FragmentStatePagerAdapter {
    SparseArray registeredFragments = new SparseArray();
    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 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 fragments, FragmentManager fm) {
        super(fm);
        this.fragments = fragments;
    }
    List fragments;
    SparseArray 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。

你可能感兴趣的:(Fragment 注意事项)