1、关于fragment的生命周期问题
fragment有多个版本,从最早的android.app,到后面的support.v4,再到现在的androidx,各个版本都有不同,也修复了一些bug,fragment需要依赖于fragmentactivity才可以使用。 他的生命周期如下图所示:

· 在执行add的时候,经过以下几个方法:
onAttach->onCreate->onCreateView->onActivityCreated->onStart->onResume
· remove的时候
onPause -> onStop-> onDestoryView -> onDestory -> onDetach
· detach
onPause->onStop->onDestoryView
· attach
onCreateView->onActivityCreated ->onStart -> onResume
· hide
会调用onHiddenChanged()
· setRetainInstance
如果调用了setRetainInstance(true)的fragment不会销毁实例,只会销毁视图并detach,不会执行onDestory,具体看下面的代码:

这个方法有什么用,在MVVM框架中,通常可以设置一个viewmodel给fragment就可以通过下面的方式来获取保存的数据:
public static <T> T findViewModel(@NonNull FragmentManager fragmentManager, String viewModelTag) {
ViewModelHolder<T> retainedViewModel =
(ViewModelHolder<T>) fragmentManager
.findFragmentByTag(viewModelTag);
if (retainedViewModel != null && retainedViewModel.getViewModel() != null) {
return retainedViewModel.getViewModel();
}
return null;
}
2、当在viewpager中使用fragment时候,需要注意的事项:
·如果是嵌套的fragment中使用viewpager,在初始化adapter的时候,不能使用getSupportManager,而应该使用getChildSupportManager,否则会报错。
/**
返回一个fragmentmanager,如果是嵌套使用的fragment
* Return a private FragmentManager for placing and managing Fragments
* inside of this Fragment.
*/
@NonNull
final public FragmentManager getChildFragmentManager() {
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " has not been attached yet.");
}
return mChildFragmentManager;
}
·viewpager中的adapter 系统有提供了两个PagerAdapter的实现类


@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
+ " v=" + ((Fragment)object).getView());
//只对fragment进行detach操作,并没有remove,这时候只是销毁了视图,他的实例还在的
mCurTransaction.detach((Fragment)object);
}
接下来看看FragmentStatePagerAdapter如何初始化instantiateItem
public Object instantiateItem(@NonNull ViewGroup container, int position) {
// If we already have this item instantiated, there is nothing
// to do. This can happen when we are restoring the entire pager
// from its saved state, where the fragment manager has already
// taken care of restoring the fragments we previously had instantiated.
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);
if (mSavedState.size() > position) {
Fragment.SavedState fss = mSavedState.get(position);
if (fss != null) {
fragment.setInitialSavedState(fss);
}
}
while (mFragments.size() <= position) {
//先初始化fragment数组
mFragments.add(null);
}
fragment.setMenuVisibility(false);
if (mBehavior == BEHAVIOR_SET_USER_VISIBLE_HINT) {
fragment.setUserVisibleHint(false);
}
//添加fragment
mFragments.set(position, fragment);
mCurTransaction.add(container.getId(), fragment);
if (mBehavior == BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {
mCurTransaction.setMaxLifecycle(fragment, Lifecycle.State.STARTED);
}
return fragment;
}
上面的注释都写的很清楚了,应该可以看懂,再来看看destroyItem
@Override
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull 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);
}
//先保存当前的状态
mSavedState.set(position, fragment.isAdded()
? mFragmentManager.saveFragmentInstanceState(fragment) : null);
//设置当前的frament为空
mFragments.set(position, null);
//在栈中移除当前这个fragment,这时候会走destory,并且数据也会丢失,需要另外做处理
mCurTransaction.remove(fragment);
}
看完上面的两个分析应该知道这两个adapter该用在什么场景下了吧,当item比较少的时候,可以用FragmentPagerAdapter,因为item较少,不会加载很多的界面,所以内存方面可以控制的,不会加载大量的内存,如果是item有很多的话,比如类似头条那种的,那就应该使用FragmentStatePagerAdapter来做,这样可以保证内存的及时回收,而不会导致oom的问题。
3、如何防止viewpager的缓存item回收
·如果item不多的话,可以设置这个方法:setOffscreenPageLimit,这个在item可控制的情况下,可以这么设置,在比较多的item的情况下,不建议使用这个
·重写destroyItem,类似下面这样
override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
// super.destroyItem(container, position, `object`)
}
未完待续。。。
以上的内容参考:www.jianshu.com/p/3d27ddc95…