PagerAdapter VS FragmentPagerAdapter VS FragmentStatePagerAdapter

ViewPager是一个负责翻页的ViewGroup,需和PagerAdapter配合数据绑定以及生成最终的View
PageAdapter,FragmentPagerAdapter,FragmentStatePagerAdapter之间的区别,需分情况使用这三个adapter
PagerAdapter:当所要展示的视图比较简单时适用
FragmentPagerAdapter:当所要展示的视图是Fragment,并且数量比较少时适用,会缓存所有Fragment,适用于相对静态的页
FragmentStatePagerAdapter:当所要展示的视图是Fragment,并且数量比较多时适用,适用于需要处理有很多页,并且数据动态性较大、占用内存较多的情况

PagerAdapter

1、PagerAdapter是FragmentPagerAdapter和FragmentStatePagerAdapter的基类
2、若需展示自定义view(非fragment),至少继承并重写它的如下方法

  • instantiateItem(ViewGroup, int)
    用来inflate view from xml并添加到ViewGroup(是ViewPager的引用)中,在每次ViewPager需要一个用以显示的Object的时候,该函数都会被调用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
    // Inflate a new layout from our resources
    View view = mLayoutInflater.inflate(R.layout.photo_layout, container, false);
    // Retrieve a TextView from the inflated View, and update it's text
    TextView titleTextView = (TextView) view.findViewById(R.id.title);
    Utils.DummyItem dummyItem = mDummyItems.get(position);
    titleTextView.setText(dummyItem.getImageTitle());
    ImageView imageView = (ImageView) view.findViewById(R.id.image);
    ImageLoaderUtil.downloadImage(dummyItem.getImageUrl(), imageView);
    view.setTag(dummyItem);
    // Add the newly created View to the ViewPager
    container.addView(view);
    // Return the View
    return view;
    }
  • destroyItem(ViewGroup, int, Object)
    PagerAdapter默认缓存3个子项(当前view及前一个和后一个子项),当滑动时其它销毁的子项会调用destroyItem

    1
    2
    3
    4
    5
    6
    7
    8
    9
    /**
    * Destroy the item from the {@link android.support.v4.view.ViewPager}. In our case this is simply removing the
    * {@link View}.
    */
    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
    container.removeView((View) object);
    Log.i(TAG, "destroyItem() [position: " + position + "]" + " childCount:" + container.getChildCount());
    }
  • getCount()

    1
    2
    3
    4
    @Override
    public int getCount() {
    return (null == mLists ? 0 : mLists.size());
    }
  • isViewFromObject(View, Object)

    1
    2
    3
    4
    5
    6
    7
    8
    /**
    * @return true if the value returned from {@link #instantiateItem(ViewGroup, int)} is the
    * same object as the {@link View} added to the {@link android.support.v4.view.ViewPager}.
    */
    @Override
    public boolean isViewFromObject(View view, Object object) {
    return object == view;
    }

FragmentPagerAdapter

1、会缓存所有Fragment,一旦一个fragment被创建,就不会被销毁,被销毁的只是fragment的视图层次,它会被FragmentManager保存起来。
fragment第一次被创建时,依次执行onAttach(), onCreate(), onCreateView(), onViewCreated(), onActivityCreated(), onViewStateRestored(), onStart(), onResume()
fragment不在屏幕显示时,依次执行onPause(), onStop(), onDestroyView(),并用于不会执行onDestroy()和onDetach()
fragment再次显示时,会从FragmentManager中获取,依次执行onCreateView(), onViewCreated(), onActivityCreated(), onViewStateRestored(), onStart(), onResume()
ps:当ViewPager设置了setOffscreenPageLimit()生命周期根据具体情况而定

2、至少需实现getItem()及getCount()

  • getItem()

instantiateItem()函数中判断一下要生成的 Fragment 是否已经生成过了,如果生成过了,就使用旧的,旧的将被 Fragment.attach();如果没有,就调用 getItem() 生成一个新的,新的对象将被 FragmentTransation.add()。
如果需要向 Fragment 对象传递相对静态的数据时,一般通过 Fragment.setArguments() ,这部分代码应当放到 getItem()。它们只会在新生成 Fragment 对象时执行一遍。
如果需要在生成 Fragment 对象后,将数据集里面一些动态的数据传递给该 Fragment,那么这部分代码不适合放到 getItem() 中,这部分代码应该放到这个函数的重载里。因为当数据集发生变化时,往往对应的 Fragment 已经生成,如果传递数据部分代码放到了 getItem() 中,这部分代码将不会被调用。这也是为什么调用 PagerAdapter.notifyDataSetChanged() 后,getItem() 没有被调用的一个原因。

1
2
3
4
5
6
7
8
9
@Override
public Fragment getItem(int position) {
return fragmentList.get(position);
}
@Override
public int getCount() {
return (fragmentList == null ? 0 : fragmentList.size());
}

FragmentStatePagerAdapter

1、与FragmentPagerAdapter不同的地方在于,当Fragment离开视线时则被消除。
2、调用destroyItem()函数,将 Fragment 移除,即调用 FragmentTransaction.remove(),并释放其资源。

BaseFragment封装

根据项目需求,以下封装了一个Fragment基类,包含加载一次数据的函数loadOnceData(),可设置BaseFragment子类的isLoadedOnce = false;来重置loadOnceData()数据重新加载一次

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
public abstract class BaseFragment extends Fragment {
protected String TAG = this.getClass().getSimpleName();
protected BaseActivity mActivity;
protected View mRootView;
protected boolean isLoadedOnce = false;
// Abstract - M
protected abstract void initValues();
protected abstract int getLayoutId();
protected abstract void initView(View view, Bundle savedInstanceState);
protected abstract void loadData();
protected abstract void loadOnceData();
// End Abstract - M
// lifecycle
// avoid getActivity return null
@Override
public void onAttach(Context context) {
super.onAttach(context);
this.mActivity = (MainTabActivity) context;
Logger.d(TAG, "onAttach");
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
this.mActivity = (MainTabActivity) activity;
Logger.d(TAG, "onAttach");
}
// create fragment
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initValues();
Logger.d(TAG, "onCreate initValues");
}
// init fragment view
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (mRootView == null) {
mRootView = LayoutInflater.from(mActivity)
.inflate(getLayoutId(), container, false);
}
initView(mRootView, savedInstanceState);
Logger.d(TAG, "onCreateView initView");
return mRootView;
}
// finish create activity
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
loadData();
Logger.d(TAG, "onActivityCreated loadData");
}
@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
super.onViewStateRestored(savedInstanceState);
Logger.d(TAG, "onViewStateRestored");
}
@Override
public void onStart() {
super.onStart();
Logger.d(TAG, "onStart");
}
@Override
public void onResume() {
super.onResume();
Logger.d(TAG, "onResume getUserVisibleHint:" + getUserVisibleHint());
if (getUserVisibleHint() && !isLoadedOnce) {
loadOnceData();
isLoadedOnce = true;
}
}
@Override
public void setUserVisibleHint(boolean isVisibleToUser) {
super.setUserVisibleHint(isVisibleToUser);
Logger.d(TAG, "isVisibleToUser:" + isVisibleToUser + " isVisible:" + isVisible() + " isLoadedOnce:" + isLoadedOnce);
if (isVisible()) {
if (isVisibleToUser && !isLoadedOnce) {
loadOnceData();
isLoadedOnce = true;
}
}
}
// End lifecycle
}