从FragmentPagerAdapter说起
我们经常使用的是ViewPager和Fragment的配合。
在第一篇中我们提到了如果ViewPager使用了FragmentPagerAdapter,ViewPager添加View的时机是在onMeasure()的populate()中。
//ViewPager.java
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
...
// Make sure we have created all fragments that we need to have shown.
populate();
...
}
populate()会调用到addNewItem()来初始化所有需要缓存的页面信息。用到了ViewPagerAdapter的instantiateItem()。
//ViewPager.java
ItemInfo addNewItem(int position, int index) {
ItemInfo ii = new ItemInfo();
ii.position = position;
ii.object = mAdapter.instantiateItem(this, position);
ii.widthFactor = mAdapter.getPageWidth(position);
if (index < 0 || index >= mItems.size()) {
mItems.add(ii);
} else {
mItems.add(index, ii);
}
return ii;
}
以FragmentPagerAdapter为例,我们看下它的instantiateItem()。主要做了这么几件事:
1.开启Transaction
2.获得Fragment并做相应动作(可能是recreate后再FragmentManager中恢复的,也可能是第一次添加)
3.设置MenuVisibility和UserVisibleHint
//FragmentPagerAdapter.java
@Override
public Object instantiateItem(ViewGroup container, int position) {
//1
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
//2
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
...
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
...
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
//3
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
之后ViewPager会在populate()中调用finishUpdate()提交事务,然后Fragment就交给了对应的FragmentManager管理,与Activity的生命周期同步。
//ViewPager.java
void populate(int newCurrentItem) {
...
mAdapter.finishUpdate(this);
...
}
//FragmentPagerAdapter.java
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
mCurTransaction.commitAllowingStateLoss();
mCurTransaction = null;
mFragmentManager.executePendingTransactions();
}
}
我们知道在Fragment和Activity生命周期同步的时候,会把自身的View添加到一个Container中,而这个Container就是在ViewPager。
之后对应的FragmentManager管理着所有Fragment的状态,如果ViewPager显示出来了,那么此时所有Fragment的状态是Resumed。也就是说所有缓存的Fragment的状态是和Activity同步的,不管它有没有作为ViewPager的主显示。
而ViewPager的滑动会通过FragmentPagerAdapter的instantiateItem()和destroyItem()造成个别Fragment的生命周期发生改变。
验证
我进行了简单的生命周期的验证,一个ViewPager下设置了4个Fragment(编号为1234),配合ViewPagerAdapter,默认缓存页面信息是1个,开始时页面在第1个。下面直接把Log信息贴上来。
图1是初始化的时候,由于缓存了1个页面信息,所以1和2会走相应的生命周期。(这里实在没有想清楚1和2的生命周期会交替进行,希望懂的朋友指点一下)