ViewPager Adapter FragmentStatePagerAdapter FragmentPagerAdapter 使用詳解

ViewPager 是Android 開發中特別常用的一個View
所以我們今天來看看ViewPager

ViewPager  是support-v4中的View
<android.support.v4.view.ViewPager

    android:id="@+id/view_pager"

    android:layout_width="match_parent"

    android:layout_height="match_parent"/>



這片文章重點的講的是ViewPager 的Adapter,
我使用 ViewPager 的Adapter 時, 一般有三種實現方式:
  1. 自己繼承 PagerAdapter
  2. 繼承FragmentPagerAdapter
  3. 繼承FragmentStatePagerAdapter

先來說說第一種:

先來代碼: 

public class ViewPagerAdapter1 extends PagerAdapter {
    public static final String TAG = ViewPagerAdapter1.class.getSimpleName();

    private List<String> mDataList;
    private LayoutInflater mLayoutInflater;

    public ViewPagerAdapter1(Context context, List<String> dataList) {
        mDataList = dataList;
        mLayoutInflater = LayoutInflater.from(context);
    }

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

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        LogUtil.d(TAG, "instantiateItem position = " + position);
        // 這裏 必須是 null , 不然報錯
        View item = mLayoutInflater.inflate(R.layout.item_1, null);
        TextView textView = (TextView) item.findViewById(R.id.txt);
        textView.setText(mDataList.get(position));
        container.addView(item);
        return item;
    }

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

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

如上代碼 就基本實現了一個 Adapter, 

instantiateItem 方法中 加載View 並把View add到 contain(即 ViewPager)中
這裏需要注意 :
View item = mLayoutInflater.inflate(R.layout.item_1, null); 中 必須是null , 不然會出問題

在destroyItem 方法中, 需要吧View 移除

isViewFromObject 中, google 推薦我們這樣寫,

上面的代碼寫的其實是有問題的, 沒有能夠複用View , 每次都是重新加載View這樣挺好性能的
不過這個問題也好解決, 只要吧 加載過的View 保存起來即可

ok 下面說一下 FragmentPagerAdapter 與 FragmentStatePagerAdapter
代碼如下: 
public class ViewPagerAdapter2 extends FragmentPagerAdapter {
    public static final String TAG = ViewPagerAdapter2.class.getSimpleName();

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

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

    public void addFragment(Fragment fragment) {
        mFragments.add(fragment);
    }

    public void removeFragment(Fragment fragment) {
        mFragments.remove(fragment);
    }

    public void setFragments(List<Fragment> fragments) {
        mFragments = fragments;
    }

    public List<Fragment> getFragments() {
        return mFragments;
    }

    public void clear() {
        for (Fragment fragment : mFragments) {
            if (fragment != null && fragment.isAdded()) {
                fragment.onDestroy();
            }
        }
        mFragments.clear();
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        LogUtil.d(TAG, "instantiateItem position = " + position);
        return super.instantiateItem(container, position);
    }

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

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

public class ViewPagerAdapter3 extends FragmentStatePagerAdapter {
    public static final String TAG = ViewPagerAdapter3.class.getSimpleName();

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

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

    public void addFragment(Fragment fragment) {
        mFragments.add(fragment);
    }

    public void removeFragment(Fragment fragment) {
        mFragments.remove(fragment);
    }

    public void setFragments(List<Fragment> fragments) {
        mFragments = fragments;
    }

    public List<Fragment> getFragments() {
        return mFragments;
    }

    public void clear() {
        for (Fragment fragment : mFragments) {
            if (fragment != null && fragment.isAdded()) {
                fragment.onDestroy();
            }
        }
        mFragments.clear();
    }

    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        LogUtil.d(TAG, "instantiateItem position = " + position);
        return super.instantiateItem(container, position);
    }

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

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

兩者的代碼基本沒有變化,
一般只要 實現 getItem getCount 兩個方法即可
他們兩使用起來感覺上差異不大,  但是內部原理差異還是挺大的.


這裏講一下兩者的區別:
FragmentPagerAdapter
     他會把每個Fragment 都保存下來,
     他在 destroyItem 方法中, 只是把 Fragment detach 掉了並沒有銷燬 Fragment

FragmentStatePagerAdapter
     只會保存Fragment的state保存下來,
     他在  destroyItem 方法中, 會把Fragment Remove 掉,
     但是會調用Fragment的 onSaveInstanceState 方法.
     然後銷燬 Fragment

使用建議, 如果只有 3,4 個Fragment的話, 建議使用 FragmentPagerAdapter ,這樣每個 Fragment 都被保存下來,加載起來頁方便

如果Fragment 數量比較多的畫, 如一下小說閱讀器這類的畫, 還是建議使用FragmentStatePagerAdapter, 這樣就不會佔用太多的內存

可以看下 Fragment的代碼: 
public class MyFragment extends Fragment {
    public final static String TAG = "MyFragment";
    public final static String SaveInstanceStateEXTRA = "SaveInstanceStateEXTRA";

    String mData;

    public static MyFragment getInstances(String data) {
        MyFragment myFragment = new MyFragment();
        myFragment.mData = data;
        return myFragment;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        LogUtil.d(TAG, "onCreateView  mData = " + mData);
        String str = "";
        if (savedInstanceState != null) {
            str = savedInstanceState.getString("SaveInstanceStateEXTRA");
        }

        // 這裏必須是null
        View item = inflater.inflate(R.layout.item_1, null);
        TextView textView = (TextView) item.findViewById(R.id.txt);
        textView.setText(mData);
        if (!TextUtils.isEmpty(str)) {
            textView.setText(str);
        }
        return item;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putString(SaveInstanceStateEXTRA, mData + "_save");
        LogUtil.d(TAG, "onSaveInstanceState  mData = " + mData);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        LogUtil.d(TAG, "onDestroy mData = " + mData);
    }
}

如果使用的是  FragmentStatePagerAdapter 
那麼 當Fragment 在不可見(在緩存數量之外的話) 會調用 onSaveInstanceState 和 onDestroy 方法
然後當被 劃回該Fragment的時候 會調用 onCreateView 方法, 其中可以在 savedInstanceState中 獲取我們 之前保存的數據


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章