PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析

一、ViewPager和PagerAdapter

1、ViewPager的缓存机制
调用setOffscreenPageLimit(n ) 方法来设置缓存的页面,当前页面的相邻n个页面都会被缓存 
默认的n为1,当前页面的前后1个页面默认被缓存。
2、setAdapter方法 源码
public void setAdapter(PagerAdapter adapter) {
    if (mAdapter != null) {
        //清除观察者
        mAdapter.setViewPagerObserver(null);
        //设置回调,开始更新页面
        mAdapter.startUpdate(this);
        for (int i = 0; i < mItems.size(); i++) {
            final ViewPager.ItemInfo ii = mItems.get(i);
            //清除之前页面
            mAdapter.destroyItem(this, ii.position, ii.object);
        }
        //设置回调,完成更新
        mAdapter.finishUpdate(this);
        mItems.clear();
        removeNonDecorViews();
        //页面重置到第一个
        mCurItem = 0;
        //滑动到开始位置
        scrollTo(0, 0);
    }

    final PagerAdapter oldAdapter = mAdapter;
    //设置新的adapter
    mAdapter = adapter;
    mExpectedAdapterCount = 0;

    if (mAdapter != null) {
        if (mObserver == null) {
            mObserver = new ViewPager.PagerObserver();
        }
        //设置观察者
        mAdapter.setViewPagerObserver(mObserver);
        mPopulatePending = false;
        final boolean wasFirstLayout = mFirstLayout;
        mFirstLayout = true;
        //设置数据个数
        mExpectedAdapterCount = mAdapter.getCount();
        if (mRestoredCurItem >= 0) {
            //如果需要恢复数据
            mAdapter.restoreState(mRestoredAdapterState, mRestoredClassLoader);
            setCurrentItemInternal(mRestoredCurItem, false, true);
            mRestoredCurItem = -1;
            mRestoredAdapterState = null;
            mRestoredClassLoader = null;
        } else if (!wasFirstLayout) {
            //如果不是第一次layout,创建或销毁页面
            populate();
        } else {
            requestLayout();
        }
    }
    //设置监听器
    if (mAdapterChangeListener != null && oldAdapter != adapter) {
        mAdapterChangeListener.onAdapterChanged(oldAdapter, adapter);
    }
}
3、PagerAdapter常用方法:
private List datas;
class MyAdapter extends PagerAdapter{
    //返回当前有效视图的个数
    @Override
    public int getCount() {
        return datas.size();
    }

    /**
     * 该函数用来判断instantiateItem(ViewGroup, int)函数所返回来的Key与一个页面视图是否是代表的同一个视图
     * 如果相同,表示是同一个view
     */
    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==object;
    }
    //移除一个给定位置的页面
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        container.removeView((View) object);
    }

    /**
     * 创建指定位置的页面视图
     * (1)将position位置的视图,增加到conatiner中,供其创建并显示。
     * (2)返回当前的view作为此视图的key
     */
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        TextView textView = new TextView(ImageActivity.this);
        textView.setText(datas.get(position));
        container.addView(textView);
        return textView;
    }
}
4、PagerAdapter基类
public class BasePagerAdaper extends PagerAdapter {
    protected List mDateList;
    protected Context mContext;

    public BasePagerAdaper(Context context){
        if (mDateList==null){
            mDateList = new ArrayList();
        }
        this.mContext = context;
    }

    public BasePagerAdaper(Context context,List dateList) {
        if (mDateList==null){
            mDateList = new ArrayList();
        }
        this.mDateList = dateList;
        this.mContext = context;
    }

    public void setData(List dateList){
        mDateList = dateList;
        notifyDataSetChanged();
    }

    public void addData(T t){
        if (mDateList!=null){
            mDateList.add(t);
            notifyDataSetChanged();
        }
    }

    @Override
    public int getCount() {
        if (mDateList!=null){
            return mDateList.size();
        }
        return 0;
    }

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

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

    /**
     * 如果T是View的子类。
     * 如果不是需要重写此方法
     */
    @Override
    public Object instantiateItem(ViewGroup container,final int position) {
        T t= mDateList.get(position);
        container.addView((View)t);
        return t;
    }
}

二、FragmentPagerAdapter

1、部分源码
@Override
public Object instantiateItem(ViewGroup container, int position) {
    if (mCurTransaction == null) {
        mCurTransaction = mFragmentManager.beginTransaction();
    }
    //获取单个条目的id
    final long itemId = getItemId(position);

    // Do we already have this fragment?
    String name = makeFragmentName(container.getId(), itemId);
    //根据名称获取Fragment
    Fragment fragment = mFragmentManager.findFragmentByTag(name);
    if (fragment != null) {
        if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
        //如果Fragment已经添加到FragmentManager中,将view视图从附加到UI上
        mCurTransaction.attach(fragment);
    } else {
        //将Fragment添加到FragmentManager中
        fragment = getItem(position);
        if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
        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();
    }
    if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
            + " v=" + ((Fragment)object).getView());
    //将view视图从ui上移除,但是Fragment还是由FragmentManager维护。
    mCurTransaction.detach((Fragment)object);
}
2、ViewPager左右切换:
(1)首次进入position为0的Fragment
PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析_第1张图片
setUserVisibleHint  参数为true,Fragment可见
首次进入时,position 为0 和1的Fragment会调用onAttach —onResume方法
(2)首次进入position为1的Fragment
PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析_第2张图片
创建position为2的Fragment,position为1的Fragment的setUser’VisibleHint 参数为true
(3)首次进入position为2的Fragment
PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析_第3张图片
position为0的Fragment 调用了onPause、onStop、onDestroyView 。没有调用onDestroy和onDetach方法,
Fragment还由FragmentManager管理。
position为3的Fragment进行创建并缓存。position为1的Fragment不可见。
(4)再次进入position为1的Fragment
PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析_第4张图片
position为1的Fragment没有调用onAttach、onCreate方法,只是调用onCreateView将view视图重新附加到ui上并显示。
position为3的Fragment调用onStop、onDestroyView销毁视图。Fragment还由FragmentManager管理。
3、FragmentAdapter基类:
public class BaseFragmentAdapter extends FragmentPagerAdapter {
    private List fragments;
    private Fragment mCurrentFragment;

    public BaseFragmentAdapter(FragmentManager fm) {
        super(fm);
    }

    public BaseFragmentAdapter(FragmentManager fm, List fragments) {
        super(fm);
        this.fragments = fragments;
    }

    public void setFragments(List fragments){
        this.fragments = fragments;
        notifyDataSetChanged();
    }

    public void addFragment(Fragment fragment){
        if (fragments!=null){
            fragments.add(fragment);
            notifyDataSetChanged();
        }
    }

    @Override
    public Fragment getItem(int i) {
        if (fragments!=null){
            return fragments.get(i);
        }
        return null;
    }

    @Override
    public int getCount() {
        if (fragments!=null){
            return fragments.size();
        }
        return 0;
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        mCurrentFragment = (Fragment) object;
        super.setPrimaryItem(container, position, object);
    }

    /**
     * 获取当前的Fragment
     * @return
     */
    public Fragment getCurrentFragment(){
        return mCurrentFragment;
    }
}
三、FragmentStateAdapter
1、部分源码
//保存Fragment状态信息的列表
private ArrayList mSavedState = new ArrayList();
//保存Fragment实例对象的列表
private ArrayList mFragments = new ArrayList();

@Override
public Object instantiateItem(ViewGroup container, int position) {
    //获取某位置的Fragment
    if (mFragments.size() > position) {
        Fragment f = mFragments.get(position);
        if (f != null) {
            return f;
        }
    }

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

    Fragment fragment = getItem(position);
    if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
    //读取给定位置的Fragment保存的状态
    if (mSavedState.size() > position) {
        Fragment.SavedState fss = mSavedState.get(position);
        if (fss != null) {
            //用该状态对Fragment进行初始化
            fragment.setInitialSavedState(fss);
        }
    }
    while (mFragments.size() <= position) {
        mFragments.add(null);
    }
    fragment.setMenuVisibility(false);
    fragment.setUserVisibleHint(false);
    mFragments.set(position, fragment);
    //添加Fragment到FragmentManager中
    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();
    }
    if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
            + " v=" + ((Fragment)object).getView());
    while (mSavedState.size() <= position) {
        mSavedState.add(null);
    }
    //保存当前销毁的Fragment的状态
    mSavedState.set(position, fragment.isAdded()
            ? mFragmentManager.saveFragmentInstanceState(fragment) : null);
    mFragments.set(position, null);
    //移除销毁的Fragment
    mCurTransaction.remove(fragment);
}
(1)在instantiateItem方法中,创建Fragment,读取相应Fragment的状态,对其进行初始化,然后add 到FragmentManager中。
(2)在destoryItem方法中,销毁Fragment,保存Fragment的状态,通过remove移除Fragment。
2、ViewPager 左右切换
1)首次进入position为0的Fragment
PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析_第5张图片
首次进入时,position 为0 和1的Fragment会调用onAttach —onResume方法
(2)首次进入position为1的Fragment
PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析_第6张图片
创建position为2的Fragment,position为1的Fragment的setUser’VisibleHint 参数为true
(3)首次进入position为2的Fragment
PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析_第7张图片
创建position为3的Fragment,position为0的Fragment的通过onDestroy和onDetach方法进行了销毁。
(4)再次返回position为1的Fragment
PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析_第8张图片
重新创建了position为0的Fragment,但是saveInstanceState参数还保留着之前存储的数据。position为3的Fragment销毁。
3、基类:
public class BaseFragmentStateAdapter extends FragmentStatePagerAdapter {
    private List fragments;
    private Fragment mCurrentFragment;
    public BaseFragmentStateAdapter(FragmentManager fm, List fragments) {
        super(fm);
        this.fragments = fragments;
    }

    public void addFragment(Fragment fragment){
        if (fragments!=null){
            fragments.add(fragment);
            notifyDataSetChanged();
        }
    }

    @Override
    public Fragment getItem(int i) {
        if (fragments!=null){
            return fragments.get(i);
        }
        return null;
    }

    @Override
    public int getCount() {
        if (fragments!=null){
            return fragments.size();
        }
        return 0;
    }

    @Override
    public void setPrimaryItem(ViewGroup container, int position, Object object) {
        mCurrentFragment = (Fragment) object;
        super.setPrimaryItem(container, position, object);
    }
    //获取当前的Fragment
    public Fragment getCurrentFragment(){
        return mCurrentFragment;
    }
}
4、总结:
FragmentPagerAdapter  每一个生成的 Fragment 都将保存在内存之中,因此适用于那些相对静态的页,数量也比较少的那种;如果需要处理有很多页,并且数据动态性较大、占用内存较多的情况,应该使用FragmentStatePagerAdapter






你可能感兴趣的:(PagerAdapter、FragmentPagerAdapter、FragmentStatePagerAdapter相关解析)