FragmentPagerAdapter和FragmentStatePagerAdapter基本用法与区别

使用ViewPager+fragment的时候,经常使用下面几种方式

ViewPager viewPager = findViewById(R.id.viewPager);
// 方式一
viewPager.setAdapter(new PagerAdapter() {
        private String mTitles[] ;
        private List<View> mViewList;

        @Override
        public int getCount() {
            return mViewList.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return view == object;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            View view = mViewList.get(position);
            container.addView(view);
            return view;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View) object);
        }

        @Override
        public CharSequence getPageTitle(int position) {
            return mTitles[position];
        }
});

// 方式二
viewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) {
    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }
});

// 方式三
viewPager.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
    @Override
    public Fragment getItem(int position) {
        return fragments.get(position);
    }

    @Override
    public int getCount() {
        return fragments.size();
    }
});

FragmentPagerAdapter 和 FragmentStatePagerAdapter有什么区别呢?

区别一: 状态保存

FragmentPagerAdapter的实现

public class FragmentPagerAdapter{
    // 省略 
    public static final int POSITION_UNCHANGED = -1;
    public static final int POSITION_NONE = -2;

    public Parcelable saveState() {
        return null;
    }

    public void restoreState(Parcelable state, ClassLoader loader) {
        
    }
}

FragmentStatePagerAdapter的实现

 public Parcelable saveState() {
        Bundle state = null;
        if (mSavedState.size() > 0) {
            state = new Bundle();
            Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
            mSavedState.toArray(fss);
            state.putParcelableArray("states", fss);
        }
        for (int i=0; i<mFragments.size(); i++) {
            Fragment f = mFragments.get(i);
            if (f != null && f.isAdded()) {
                if (state == null) {
                    state = new Bundle();
                }
                String key = "f" + i;
                mFragmentManager.putFragment(state, key, f);
            }
        }
        return state;
    }

    @Override
    public void restoreState(Parcelable state, ClassLoader loader) {
        if (state != null) {
            Bundle bundle = (Bundle)state;
            bundle.setClassLoader(loader);
            Parcelable[] fss = bundle.getParcelableArray("states");
            mSavedState.clear();
            mFragments.clear();
            if (fss != null) {
                for (int i=0; i<fss.length; i++) {
                    mSavedState.add((Fragment.SavedState)fss[i]);
                }
            }
            Iterable<String> keys = bundle.keySet();
            for (String key: keys) {
                if (key.startsWith("f")) {
                    int index = Integer.parseInt(key.substring(1));
                    Fragment f = mFragmentManager.getFragment(bundle, key);
                    if (f != null) {
                        while (mFragments.size() <= index) {
                            mFragments.add(null);
                        }
                        f.setMenuVisibility(false);
                        mFragments.set(index, f);
                    } else {
                        Log.w(TAG, "Bad fragment at key " + key);
                    }
                }
            }
        }
    }

可以很容易看出只有FragmentStatePagerAdapter对Fragment的状态进行了保存,而FragmentPagerAdapter则是空实现。因为ViewPager持有Adapter实例,所以ViewPager的onSaveInstanceState和onRestoreInstanceState方法都是间接调用Adapter来执行状态的恢复和保存的,我们看到ViewPager中间接调用了mAdapter.saveState()mAdapter.restoreState。

区别二: 实例销毁 vs 视图销毁

ViewPager + FragmentPagerAdapter(FragmentStatePagerAdapter) 仅仅实现getItem和getCount两个方法就够了,核心方法instantiateItem和destroyItem内部已经做好了实现。

FragmentStatePagerAdapter类

private ArrayList<Fragment> mFragments = new ArrayList<Fragment>();

 public Object instantiateItem(ViewGroup container, int position) {
        if (mFragments.size() > position) {
            Fragment f = mFragments.get(position);
            if (f != null) {
                return f;
            }
        }

        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }

        // 实例化fragment(交给我们实现的getItem方法)
        Fragment fragment = getItem(position);

        if (mSavedState.size() > position) {
            Fragment.SavedState fss = mSavedState.get(position);
            if (fss != null) {
                fragment.setInitialSavedState(fss);
            }
        }
        // 如果缓存 <= ViewPager传入的position,说明当前位置还未存入缓存.
        while (mFragments.size() <= position) {
            // 先占个坑
            mFragments.add(null);
        }
        fragment.setUserVisibleHint(false);
        // 填坑
        mFragments.set(position, fragment);
        // 填充视图
        mCurTransaction.add(container.getId(), fragment);
        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;

        if (mCurTransaction == null) {
            mCurTransaction = mFragmentManager.beginTransaction();
        }
        // 从缓存中移除
        mFragments.set(position, null);
        // 从FragmentManager中移除
        mCurTransaction.remove(fragment);
    }

FragmentPagerAdapter

@Override
public Object instantiateItem(ViewGroup container, int position) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }

    final long itemId = getItemId(position);

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    if (fragment != null) {
        mCurTransaction.attach(fragment);
    } else {
        fragment = getItem(position);
        mCurTransaction.add(container.getId(), fragment,
                makeFragmentName(container.getId(), itemId));
    }
    if (fragment != mCurrentPrimaryItem) {
        fragment.setMenuVisibility(false);
        fragment.setUserVisibleHint(false);
    }

    return fragment;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }
    mCurTransaction.detach((Fragment)object);
}

FragmentStatePagerAdapter 内部还做了个小缓存,重点下面

//FragmentStatePagerAdapter

mCurTransaction.add(container.getId(), fragment);
mCurTransaction.remove(fragment);

//FragmentPagerAdapter

mCurTransaction.attach(fragment);
mCurTransaction.add(container.getId(), fragment,makeFragmentName(container.getId(), itemId));
mCurTransaction.detach((Fragment)object);

FragmentStatePagerAdapter 对fragment进行完全的添加和删除操作,而FragmentPagerAdapter 则是对视图进行attach和detach。

总结:
FragmentStatePagerAdapter 适合大量页面,不断重建和销毁
FragmentPagerAdapter 适合少量页面,常驻内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值