ViewPager淺析(一)

ViewPager在開發(fā)中的使用頻率非常的高,所以在此做個總結(jié)。

一、簡介

1.ViewPager的簡介和作用
ViewPager是android擴(kuò)展包v4包中的類,這個類可以讓用戶左右切換當(dāng)前的view1)ViewPager類直接繼承了ViewGroup類,所有它是一個容器類,可以在其中添加其他的view類。2)ViewPager類需要一個PagerAdapter適配器類給它提供數(shù)據(jù)。3)ViewPager經(jīng)常和Fragment一起使用,并且提供了專門的FragmentPagerAdapter和FragmentStatePagerAdapter類供Fragment中的ViewPager使用。

2.ViewPager的適配器
簡介中提到了PagerAdapter,和ListView等控件使用一樣,需要ViewPager設(shè)置PagerAdapter來完成頁面和數(shù)據(jù)的綁定,這個PagerAdapter是一個基類適配器,我們經(jīng)常用它來實(shí)現(xiàn)app引導(dǎo)圖,它的子類有FragmentPagerAdapter和FragmentStatePagerAdapter,這兩個子類適配器用于和Fragment一起使用,在安卓應(yīng)用中它們就像listview一樣出現(xiàn)的頻繁。

二、Adapter的工具類

這里只是做了最簡單的封裝,可以根據(jù)需要調(diào)整

PagerAdapter工具類

public class QuickPageAdapter<T extends View> extends PagerAdapter {
        private List<T> mList;

        public QuickPageAdapter(List<T> mList) {
            this.mList = mList;
        }

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

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

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(mList.get(position));
            return mList.get(position);
        }

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

使用

List<View> views = new ArrayList<>();
mViewPager.setAdapter(new QuickPageAdapter<View>(views));

FragmentPagerAdapter工具類

public class QuickFragmentPageAdapter<T extends Fragment> extends FragmentPagerAdapter {
        private List<T> mList;
        private String[] mStrings;

        /**
         * @param fm
         * @param list
         * @param titles PageTitles
         */
        public QuickFragmentPageAdapter(FragmentManager fm, List<T> list, String[] titles) {
            super(fm);
            mList = list;
            mStrings = titles;
        }

        @Override
        public Fragment getItem(int position) {
            return mList.get(position);
        }

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

        @Override
        public CharSequence getPageTitle(int position) {
            return mStrings == null ? super.getPageTitle(position) : mStrings[position];
        }
    }

FragmentStatePagerAdapter封裝類似FragmentPagerAdapter就不寫了,基本使用講完了。

三、源碼淺析

FragmentPagerAdapter和FragmentStatePagerAdapter的區(qū)別,你造嗎?

先上源碼

<ul>
<li> FragmentStatePagerAdapter</li>
</ul>

@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);//fragment被釋放后這里得到的null值
            if (f != null) {
                return f;
            }
        }

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

        Fragment fragment = getItem(position);//fragment被釋放后或者是初次進(jìn)入頁面拿到新的Fragment實(shí)例
        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);//新的Fragment實(shí)例 是add上去的

        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);//真正釋放了fragment實(shí)例

        mCurTransaction.remove(fragment);
    }

<ul>
<li> FragmentPagerAdapter</li>
</ul>

@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);//因?yàn)閒ragment實(shí)例沒有被真正釋放,所以可以直接attach效率高
        } else {
            fragment = getItem(position);//初始化頁面的時候拿到fragment的實(shí)例
            if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
            mCurTransaction.add(container.getId(), fragment,
                    makeFragmentName(container.getId(), itemId));//add上去
        }
        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);//并沒有真正釋放fragment對象只是detach
    }

小結(jié)

?????從源碼中我們可以看出FragmentStatePagerAdapter中fragment實(shí)例在destroyItem的時候被真正釋放,所以FragmentStatePagerAdapter省內(nèi)存。FragmentPagerAdapter中的fragment實(shí)例在destroyItem的時候并沒有真正釋放fragment對象只是detach,也就是說,F(xiàn)ragmentPagerAdapter銷毀的是Fragment的視圖,而FragmentStatePagerAdapter銷毀的是實(shí)例對象,所以FragmentPagerAdapter消耗更多的內(nèi)存,帶來的好處就是效率更高一些。所以得出這樣的結(jié)論:FragmentPagerAdapter適用于頁面比較少的情況,F(xiàn)ragmentStatePagerAdapter適用于頁面比較多的情況,因此不同的場合選擇合適的適配器才是正確的做法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容