记录下博客地址:
https://blog.csdn.net/czhpxl007/article/details/51277319
以及FragmentPageAdapter 和 FragmentStatePageAdapter对Fragment的生命周期的影响
问题:项目中ViewPage的setcurrentItem(itempostion) 切换Fragment的时候,发现fragment的数据没有刷新;然后打印它的生命周期方法,均没有执行。原因是预加载设置: mViewPager.setOffscreenPageLimit(mTabTitles.length - 1);
当你宿主Activity加载时候,你的Fragment会全部被创建加载进来。主要方法调用PagerAdapter的实现类FragmentPagerAdapter or FragmentStatePagerAdapter的instantiateItem()方法;如果你查看源码会发现,这个方法走了FragmetTransation的一系列方法,现在贴一下源码:
FragmentStatePagerAdapter.java
@NonNull
public Object instantiateItem(@NonNull ViewGroup container, int position) {
Fragment fragment;
if (this.mFragments.size() > position) {
fragment = (Fragment)this.mFragments.get(position);
if (fragment != null) {
return fragment;
}
}
if (this.mCurTransaction == null) {
this.mCurTransaction = this.mFragmentManager.beginTransaction();
}
fragment = this.getItem(position);
if (this.mSavedState.size() > position) {
SavedState fss = (SavedState)this.mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
while(this.mFragments.size() <= position) {
this.mFragments.add((Object)null);
}
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
this.mFragments.set(position, fragment);
this.mCurTransaction.add(container.getId(), fragment);
return fragment;
}
FragmentPagerAdapter.java里的方法
public Object instantiateItem(@NonNull ViewGroup container, int position) {
if (this.mCurTransaction == null) {
this.mCurTransaction = this.mFragmentManager.beginTransaction();
}
long itemId = this.getItemId(position);
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = this.mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
this.mCurTransaction.attach(fragment);
} else {
fragment = this.getItem(position);
this.mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId));
}
if (fragment != this.mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
因此,预加载会导致不可见的Fragment一股脑的调用onCreate、onCreateView、onResume等方法,用户只能通一些方法进行识别:Fragment.setUserVisibleHint()。
一张传统fragment生命周期图,每次都忘😭😭😭😭😭😭😭😭
屏幕快照 2019-11-11 下午4.45.48.png
所以,你在调用ViewPage的setcurrentItem(itempostion) 切换Fragment,只会走fragment.setUserVisibleHint()方法,那么又有问题来了:
1.fragment是如何知道自己什么时候是用户可见?
2.setUserVisibleHint() 在上图所示fragment的生命周期的什么位置?
先上结论:
1.ViewPager监听Tab切换事件,每次切换tab都会走setUserVisibleHint()方法;
2.setUserVisibleHint()在所有上面的fragment生命周期 之前调用,无论ViewPager在Activity的哪个生命周期初始化
//每次切换ViewPager的Tab时调用的方法
void populate(int newCurrentItem) {
mAdapter.startUpdate(this);
//......
addNewItem(mCurItem, curIndex);
// mCurItem 为当前可见Fragment
// 调用setUserVisibleHint(true)
mAdapter.setPrimaryItem(this, mCurItem, curItem != null ? curItem.object : null);
mAdapter.finishUpdate(this);
//.....
}
ItemInfo addNewItem(int position, int index) {
ItemInfo ii = new ItemInfo();
ii.position = position;
//初始化fragment, 调用setUserVisibleHint(false)
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;
}
meworks/support/v4/java/android/support/v4/app/FragmentPagerAdapter.java
@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);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
//将fragment添加到FragmentManager里面
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
//我们要找的方法在这里
fragment.setUserVisibleHint(false);
}
return 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;
}
}
所以,这里可以看到,每次setCurrentItem()的时候,都会调用到setCurrentItemInternal{
//...
populate(item);
//...
}
然后poulate()一路调用到 fragment.setUserVisibleHint(true);
接着,看Activity中对fragment的生命周期的管理:










网友评论