ViewPager
与Fragment
的配合使用,除了FragmentPagerAdapter
之外,还有另外一个选择FragmentStatePagerAdapter
。
从名称上来看,FragmentStatePagerAdapter
多了个状态标志,这表明其与FragmentPagerAdapter
的差别应该就是状态的问题了。我们可以通过源代码来了解。
FragmentStatePagerAdapter
相对于FragmentPagerAdapter
多了两个全局变量:
private ArrayList mSavedState = new ArrayList();
private ArrayList mFragments = new ArrayList();
- mSavedState 保存每个
Fragment
的状态信息的列表 - mFragments 保存每个
Fragment
实例对象的列表
FragmentStatePagerAdapter
添加的方法与FragmentPagerAdapter
基本一致,重载的方法则进行了部分调整:
/**
* 获取给定位置对应的Fragment。
*
* @param position 给定的位置
* @return 对应的Fragment
*/
public abstract Fragment getItem(int position);
@Override
public void startUpdate(ViewGroup container) {
}
@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 fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
// 读取给定位置的Fragment保存的状态,并用该状态对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);
// 添加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);
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
// 主要项切换,相关菜单及信息进行切换
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
// 提交事务
mCurTransaction.commitAllowingStateLoss();
mCurTransaction = null;
// 立即运行等待中事务
mFragmentManager.executePendingTransactions();
}
}
@Override
public boolean isViewFromObject(View view, Object object) {
return ((Fragment)object).getView() == view;
}
@Override
public Parcelable saveState() {
Bundle state = null;
if (mSavedState.size() > 0) {
// 保存Fragment状态列表
state = new Bundle();
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
mSavedState.toArray(fss);
state.putParcelableArray("states", fss);
}
// 保存Fragment列表
for (int i=0; i keys = bundle.keySet();
for (String key: keys) {
if (key.startsWith("f")) {
int index = Integer.parseInt(key.substring(1));
Fragment f = mFragmentManager.getFragment(bundle, key);
if (f != null) {
while (mFragments.size() <= index) {
mFragments.add(null);
}
f.setMenuVisibility(false);
mFragments.set(index, f);
} else {
Log.w(TAG, "Bad fragment at key " + key);
}
}
}
}
}
从源代码中,我们可以清楚了解到FragmentStatePagerAdapter
与FragmentPagerAdapter
的不同:
-
FragmentStatePagerAdapter
对Fragment实例和Fragment状态进行引用保留。 -
FragmentStatePagerAdapter
在instantiateItem
方法中,创建新Fragment
后,读取对应Fragment状态对其进行初始化设置,并且只使用到add方法。 -
FragmentStatePagerAdapter
在destroyItem
方法中,销毁Fragment
时,保存其Fragment状态,并且使用remove方法移除Fragment
。 -
FragmentStatePagerAdapter
重载了saveState
方法和restoreState
方法,在其中对于Fragment实例列表和Fragment状态列表进行保存和读取。
我们可以创建个简单应用,并且按照以下逻辑进行操作,查看相关LOG,来进一步了解:
①首次进入默认Fragment1:
I: StatePagerActivity onCreate null
I: StatePagerActivity onStart
I: StatePagerActivity onResume
I: Fragment1 setUserVisibleHint false
I: Fragment2 setUserVisibleHint false
I: Fragment1 onAttach
I: Fragment1 onCreate null
I: Fragment1 setUserVisibleHint true
I: Fragment2 onAttach
I: Fragment2 onCreate null
I: Fragment2 onCreateView null
I: Fragment2 onViewCreated
I: Fragment2 onActivityCreated null
I: Fragment2 onViewStateRestored null
I: Fragment1 onCreateView null
I: Fragment1 onViewCreated
I: Fragment1 onActivityCreated null
I: Fragment1 onViewStateRestored null
I: Fragment1 onStart
I: Fragment1 onResume
I: Fragment2 onStart
I: Fragment2 onResume
②点击Fragment2:
I: Fragment3 setUserVisibleHint false
I: Fragment1 setUserVisibleHint false
I: Fragment2 setUserVisibleHint true
I: Fragment3 onAttach
I: Fragment3 onCreate null
I: Fragment3 onCreateView null
I: Fragment3 onViewCreated
I: Fragment3 onActivityCreated null
I: Fragment3 onViewStateRestored null
I: Fragment3 onStart
I: Fragment3 onResume
③点击Fragment3:
I: Fragment1 onSaveInstanceState Bundle[{}]
I: Fragment4 setUserVisibleHint false
I: Fragment2 setUserVisibleHint false
I: Fragment3 setUserVisibleHint true
I: Fragment4 onAttach
I: Fragment4 onCreate null
I: Fragment1 onPause
I: Fragment1 onStop
I: Fragment1 onDestroyView
I: Fragment1 onDestroy
I: Fragment1 onDetach
I: Fragment4 onCreateView null
I: Fragment4 onViewCreated
I: Fragment4 onActivityCreated null
I: Fragment4 onViewStateRestored null
I: Fragment4 onStart
I: Fragment4 onResume
④点击Fragment4:
I: Fragment4 onResume
I: Fragment2 onSaveInstanceState Bundle[{}]
I: Fragment5 setUserVisibleHint false
I: Fragment3 setUserVisibleHint false
I: Fragment4 setUserVisibleHint true
I: Fragment5 onAttach
I: Fragment5 onCreate null
I: Fragment2 onPause
I: Fragment2 onStop
I: Fragment2 onDestroyView
I: Fragment2 onDestroy
I: Fragment2 onDetach
I: Fragment5 onCreateView null
I: Fragment5 onViewCreated
I: Fragment5 onActivityCreated null
I: Fragment5 onViewStateRestored null
I: Fragment5 onStart
I: Fragment5 onResume
⑤点击Fragment5:
I: Fragment3 onSaveInstanceState Bundle[{}]
I: Fragment4 setUserVisibleHint false
I: Fragment5 setUserVisibleHint true
I: Fragment3 onPause
I: Fragment3 onStop
I: Fragment3 onDestroyView
I: Fragment3 onDestroy
I: Fragment3 onDetach
⑥进入后台:
I: Fragment5 onPause
I: Fragment4 onPause
I: StatePagerActivity onPause
I: Fragment5 onSaveInstanceState Bundle[{}]
I: Fragment4 onSaveInstanceState Bundle[{}]
I: StatePagerActivity onSaveInstanceState Bundle[{android:viewHierarchyState=Bundle[{android:views={16908290=android.view.AbsSavedState$1@878ae08, 2131492956=android.view.AbsSavedState$1@878ae08, 2131492957=android.view.AbsSavedState$1@878ae08, 2131492958=android.support.v7.widget.Toolbar$SavedState@298b9a1, 2131492959=android.view.AbsSavedState$1@878ae08, 2131492976=FragmentPager.SavedState{71c47c6 position=4}, 2131492977=HorizontalScrollView.SavedState{e0d1387 scrollPosition=0}}}], android:support:fragments=android.support.v4.app.FragmentManagerState@8eea2b4}]
I: Fragment5 onStop
I: Fragment4 onStop
I: StatePagerActivity onStop
⑦返回前台:
I: Fragment5 onStart
I: Fragment4 onStart
I: StatePagerActivity onStart
I: StatePagerActivity onResume
I: Fragment5 onResume
I: Fragment4 onResume
⑧点击Fragment4:
I: Fragment3 setUserVisibleHint false
I: Fragment5 setUserVisibleHint false
I: Fragment4 setUserVisibleHint true
I: Fragment3 onAttach
I: Fragment3 onCreate Bundle[{android:user_visible_hint=false}]
I: Fragment3 onCreateView Bundle[{android:user_visible_hint=false}]
I: Fragment3 onViewCreated
I: Fragment3 onActivityCreated Bundle[{android:user_visible_hint=false}]
I: Fragment3 onViewStateRestored Bundle[{android:user_visible_hint=false}]
I: Fragment3 onStart
I: Fragment3 onResume
通过LOG,可以进一步了解到FragmentStatePagerAdapter
与FragmentPagerAdapter
的不同:
-
Fragment
在FragmentStatePagerAdapter
类的destroyItem
方法中被remove时,Fragment
的onDestroy
方法和onDetach
方法都被调用到。 - 当Fragment重新被add时,Fragment的生命周期全部重新调用,但是savedInstanceState参数保留着之前存储的数据。