FragmentStatePagerAdapter与FragmentPagerAdapter的区别与使用场景

ViewPager是android扩展包v4包中的类,这个类可以让用户左右切换当前的view

1)ViewPager类直接继承了ViewGroup类,所有它是一个容器类,可以在其中添加其他的view类。

2)ViewPager类需要一个PagerAdapter适配器类给它提供数据,适用于View。

3)ViewPager经常和Fragment一起使用,并且提供了专门的FragmentPagerAdapter和FragmentStatePagerAdapter类供Fragment中的ViewPager使用,注意使用的是v4的Fragment。

 

//PagerAdapter最基本的使用,必须实现四个方法
public class AdapterViewpager extends PagerAdapter {
    private List mViewList;

    public AdapterViewpager(List mViewList) {
        this.mViewList = mViewList;
    }

    @Override
    public int getCount() {//必须实现
        return mViewList.size();
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {//必须实现,判断容器里的View是否与一个key值相关联,比如说例如Fragment+ViewPager的处理,每个页面都由它是对应的Fragment来呈现,但ViewPager并不是直接与View关联,而是关联一个key。
        return view == object;
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {//必须实现,父类未实例化
        container.addView(mViewList.get(position));
        return mViewList.get(position);
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {//必须实现,父类未实例化
        container.removeView(mViewList.get(position));
    }
}

FragmentStatePagerAdapter的实现和FragmentPagerAdapter的实现一样:

 

public class AdapterFragment extends FragmentPagerAdapter {
    private List mFragments;

    public AdapterFragment(FragmentManager fm, List mFragments) {
        super(fm);
        this.mFragments = mFragments;
    }

    @Override
    public Fragment getItem(int position) {//必须实现
        return mFragments.get(position);
    }

    @Override
    public int getCount() {//必须实现
        return mFragments.size();
    }

    @Override
    public CharSequence getPageTitle(int position) {//选择性实现
        return mFragments.get(position).getClass().getSimpleName();
    }
}

FragmentStatePagerAdapter与FragmentPagerAdapter的不同:

FragmentStatePagerAdapter类名中的“state”表明:在销毁fragment时,调用remove(Fragment)将fragment从FragmentManager中彻底移除。可在fragment的onSaveInstanceState(Bundle)方法中保存fragment的状态信息。在用户切换回来时,保存的实例状态可用来恢复生成新的fragment。当页面离开视线后,就会被消除,释放其资源;而在页面需要显示时,生成新的页面(就像 ListView 的实现一样)。这么实现的好处就是当拥有大量的页面时,不必在内存中占用大量的内存。

对于不再需要的fragment,FragmentPagerAdapter会调用detach(Fragment)方法来处理,而不是remove(Fragment)。所以FragmentPagerAdapter只是销毁了fragment的视图,fragment实例还保留在FragmentManager中。因此,FragmentPagerAdapter创建的fragment永远不会被销毁。
通过Fragment fragment = mFragmentManager.findFragmentByTag(name)进行旧的Fragment的读取.。


FragmentStatePagerAdapter在instantiateItem方法中,创建新Fragment后,读取对应Fragment状态对其进行初始化设置,并且只使用到add方法;FragmentPagerAdapter使用Transaction设置Tag进行add。
FragmentStatePagerAdapter在destroyItem方法中,销毁Fragment时,保存其Fragment状态,并且使用remove方法移除Fragment,同时设置mFragments中对应位置为空。


FragmentPagerAdapter销毁时使用的是mCurTransaction.detach((Fragment)object);//并没有真正释放fragment对象只是detach。
FragmentStatePagerAdapter重载了saveState方法和restoreState方法,在其中对于Fragment实例列表和Fragment状态列表进行保存和读取。

 

FragmentStatePagerAdapter源码:

@Override
    public Object instantiateItem(ViewGroup container, int position) {
        // If we already have this item instantiated, there is nothing
        // to do.  This can happen when we are restoring the entire pager
        // from its saved state, where the fragment manager has already
        // taken care of restoring the fragments we previously had instantiated.
        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);
        if (mSavedState.size() > position) {
            Fragment.SavedState fss = mSavedState.get(position);
            if (fss != null) {
                fragment.setInitialSavedState(fss);
            }
        }
        while (mFragments.size() <= position) {
            mFragments.add(null);
        }
        fragment.setMenuVisibility(false);
        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();
        }
        if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
                + " v=" + ((Fragment)object).getView());
        while (mSavedState.size() <= position) {
            mSavedState.add(null);
        }
        mSavedState.set(position, fragment.isAdded()
                ? mFragmentManager.saveFragmentInstanceState(fragment) : null);
        mFragments.set(position, null);

        mCurTransaction.remove(fragment);
    }

FragmentPagerAdapter源码:

   

    @SuppressWarnings("ReferenceEquality")
    @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) {
            if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
            mCurTransaction.attach(fragment);
        } else {
            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());
        mCurTransaction.detach((Fragment)object);
    }

 

 

FragmentPagerAdapter中的fragment实例在destroyItem的时候并没有真正释放fragment对象只是detach,所以FragmentPagerAdapter消耗更多的内存,

带来的好处就是效率更高一些。所以得出这样的结论:FragmentPagerAdapter适用于页面比较少的情况,FragmentStatePagerAdapter适用于页面比较多的情况,

因此不同的场合选择合适的适配器才是正确的做法。

FragmentPagerAdapter在切换时的效果。可见最后调用的只是onDestroyView,重新加载也不会执行onCreate方法,因此内存占用比较高:

 

 

 

FragmentStatePagerAdapter与FragmentPagerAdapter的区别与使用场景_第1张图片

 

FragmentStatePagerAdapter在切换时的效果,最终执行了onDestroy()和onDetach(),重新加载会执行onCreate方法,其缓存个数跟ViewPager的viewPager.setOffscreenPageLimit()有关,

默认是1。setOffscreenPageLimit设置的值是表示左右各缓存N个。

FragmentStatePagerAdapter与FragmentPagerAdapter的区别与使用场景_第2张图片

 

 

 

Activity与Fragment配合使用时经常遇到一个问题,当activity被销毁时重建,其上的view的状态和数据会被保存,以便数据恢复。

Activity已经被销毁,而Fragment还在,最好的解决办法就是:不保存因意外导致的状态和View,防止Activity重新创建时Fragment状态位置混乱。

 

@Override
public voidonSaveInstanceState(Bundle outState) {
//将super调用取消即可,表明当意外(比如系统内存吃紧将应用杀死)发生我不需要保存Fragmentde状态和数据等
//super.onSaveInstanceState(outState);
}

 

 

 

 

 

你可能感兴趣的:(ViewPager,PagerAdapter,Android知识回顾)