本篇主要记录Fragment源码分析以及一些容易忽视的问题。基于api28,androidx.fragment:fragment:1.0.0。
Fragment生命周期
[TOC]
1.Fragment如何被添加到Activity的?
都知道Fragment的add,replace,hide,show以及最后的commit离不开FragmentTransaction。,而FragmentTransaction最终是通过FragmentManagerImpl#beginTransaction来获取的。下面是Fragmen添加t到Activity的用法。
supportFragmentManager.beginTransaction()
.add(R.id.item_detail_container, fragment)
.commit()
FragmentManagerImpl#beginTransaction的实现如下,也就是说FragmentTransaction的实现为BackStackRecord。那么后续的add操作也就基于BackStackRecord。 下文中将BackStackRecord简称为bsr。
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
那么接着看bsr#add
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
fragment.mFragmentManager = mManager;
if (tag != null) {
fragment.mTag = tag;
}
if (containerViewId != 0) {
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
addOp(new Op(opcmd, fragment));
}
void addOp(Op op) {
mOps.add(op);
}
bsr#add将fragment以及标识为add的OP_ADD标志封装到Op对象并添加到一个叫mOps ArrayList中。 那么add方法至此就分析完毕。接下来是commit方法。
bsr#commit
public int commit() {
return commitInternal(false);
}
int commitInternal(boolean allowStateLoss) {
...
mCommitted = true;
mManager.enqueueAction(this, allowStateLoss);
...
}
FragmentManager#enqueueAction
public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
synchronized (this) {
if (mPendingActions == null) {
mPendingActions = new ArrayList<>();
}
mPendingActions.add(action);
scheduleCommit();
}
}
void scheduleCommit() {
synchronized (this) {
boolean postponeReady =
mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
if (postponeReady || pendingReady) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit);
}
}
}
到此bsrcommit操作被添加到mPendingActions List中,并往主线程handler提交一个叫mExecCommit的Runnable来完成commit操作。由此可知commt操作与Activity生命周期不同步,即在Activity#onCreate中调用commit并不是立即执行的。
mExecCommit的调用栈
Runnable mExecCommit = new Runnable() {
@Override
public void run() {
execPendingActions();
}
};
public boolean execPendingActions() {
ensureExecReady(true);
boolean didSomething = false;
while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
mExecutingActions = true;
try {
removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
} finally {
cleanupExec();
}
didSomething = true;
}
doPendingDeferredStart();
burpActive();
return didSomething;
}
ensureExecReady(true)操作执行一些动画的取消和创建mTmpRecords,mTmpIsPop这两个类型都为ArrayList。 那么看下while条件
private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isPop) {
boolean didSomething = false;
synchronized (this) {
//刚刚给mPendingActions添加了一个OpGenerator
if (mPendingActions == null || mPendingActions.size() == 0) {
return false;
}
//从这段代码分析可知generateOpsForPendingActions返回值
final int numActions = mPendingActions.size();
for (int i = 0; i < numActions; i++) {
didSomething |= mPendingActions.get(i).generateOps(records, isPop);
}
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
return didSomething;
}
刚刚给mPendingActions添加了一个OpGenerator,而OpGenerator的实现为bsr。那么由此可知generateOpsForPendingActions返回值受bsr#generateOps影响。
bsr#generateOps
public boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop) {
...
records.add(this);
isRecordPop.add(false);
...
return true;
}
generateOps默认返回true,并把bsr添加到records,即mTmpRecords中。 那么接着看while循环体中实现
private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop) {
...
final int numRecords = records.size();
int startIndex = 0;
for (int recordNum = 0; recordNum < numRecords; recordNum++) {
//默认为false
final boolean canReorder = records.get(recordNum).mReorderingAllowed;
if (!canReorder) {
executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
}
}
...
}
private void executeOpsTogether(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
...
executeOps(records, isRecordPop, startIndex, endIndex);
...
}
private static void executeOps(ArrayList<BackStackRecord> records,
ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
for (int i = startIndex; i < endIndex; i++) {
final BackStackRecord record = records.get(i);
final boolean isPop = isRecordPop.get(i);
//isPop为false
if (isPop) {
...
} else {
record.bumpBackStackNesting(1);
//执行bsr#executeOps
record.executeOps();
}
}
}
bsr#executeOps
void executeOps() {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.fragment;
...
switch (op.cmd) {
case OP_ADD:
f.setNextAnim(op.enterAnim);
mManager.addFragment(f, false);
break;
case OP_REMOVE:
f.setNextAnim(op.exitAnim);
mManager.removeFragment(f);
break;
case OP_HIDE:
f.setNextAnim(op.exitAnim);
mManager.hideFragment(f);
break;
case OP_SHOW:
f.setNextAnim(op.enterAnim);
mManager.showFragment(f);
break;
case OP_DETACH:
f.setNextAnim(op.exitAnim);
mManager.detachFragment(f);
break;
case OP_ATTACH:
f.setNextAnim(op.enterAnim);
mManager.attachFragment(f);
break;
case OP_SET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(f);
break;
case OP_UNSET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(null);
break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
...
}
//mReorderingAllowed为false
if (!mReorderingAllowed) {
mManager.moveToState(mManager.mCurState, true);
}
}
由上面bsr#executeOps分析可知由不同的操作调用FragmentManager不同的方法,这里只看add操作,所以这里调用FragmentManager#addFragment。 最后由于mReorderingAllowed为false,调用FragmentManager#moveToState方法。
FragmentManager#addFragment
public void addFragment(Fragment fragment, boolean moveToStateNow) {
makeActive(fragment);
if (!fragment.mDetached) {
synchronized (mAdded) {
mAdded.add(fragment);
}
fragment.mAdded = true;
fragment.mRemoving = false;
if (fragment.mView == null) {
fragment.mHiddenChanged = false;
}
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
if (moveToStateNow) {
moveToState(fragment);
}
}
}
makeActive操作将fragment添加到mActive SparseArray中。 FragmentManager#makeActive
void makeActive(Fragment f) {
if (f.mIndex >= 0) {
return;
}
f.setIndex(mNextFragmentIndex++, mParent);
if (mActive == null) {
mActive = new SparseArray<>();
}
mActive.put(f.mIndex, f);
}
这里说明下mActive存储Fragment时机,由于commit操作是往handler post了一个Runnable。那么导致commit操作和Activty声明周期是不同步的。而 Activity#OnStart()调用时也会调刚才分析commit的调用链(从execPendingActions开始)。也就是说execPendingActions不单单是被我们主动commit调用,而且还被Activity#onStart()调用,其实无论Fragment添加操作被谁调用,后续的主要调用方法都是一样的。总之根据addFragment可知,当前Fragment实例被添加到mActive和mAdded中。
那么接着分析bsr#executeOps中最后一个执行操作,即调用FragmentManager.moveToState(mManager.mCurState, true); 而moveToState(mManager.mCurState,true)最终会调用moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive) 所以接下来直接分析moveToState(Fragment f, int newState, int transit, int transitionStyle,boolean keepActive)
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
case Fragment.INITIALIZING:
if (newState > Fragment.INITIALIZING) {
if (f.mSavedFragmentState != null) {
//恢复状态相关
}
...
//调用Fragmnet#onAttach
f.onAttach(mHost.getContext());
if (!f.mIsCreated) {
//调用Fragment#onCreate
f.performCreate(f.mSavedFragmentState);
}
}
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
//获取Activity提供给Fragment添加的ViewGroup
container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
}
f.mContainer = container;
//调用Fragment#onCreateView
f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
//将onCreateView中获取的View添加到Activity提供给Fragment添加的ViewGroup中
if (container != null) {
container.addView(f.mView);
}
//如果是hide操作则GONE掉
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
//调用Fragment#onViewCreated
f.onViewCreated(f.mView, f.mSavedFragmentState);
}
}
//调用Fragment#onActivityCreated
f.performActivityCreated(f.mSavedFragmentState);
}
// fall through
case Fragment.ACTIVITY_CREATED:
if (newState > Fragment.ACTIVITY_CREATED) {
//调用Fragment#onStart
f.performStart();
}
// fall through
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
//调用Fragment#onResume
f.performResume();
...
}
}
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
//调用Fragment#onPause
f.performPause();
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
//调用Fragment#onStop
f.performStop();
}
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
//调用Fragment#onDestroyView
f.performDestroyView();
f.mContainer = null;
f.mView = null;
f.mViewLifecycleOwner = null;
f.mViewLifecycleOwnerLiveData.setValue(null);
f.mInnerView = null;
f.mInLayout = false;
}
// fall through
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
if (!f.mRetaining) {
//调用Fragment#onDestory
f.performDestroy();
} else {
f.mState = Fragment.INITIALIZING;
}
//调用Fragment#onDetach
f.performDetach();
}
}
}
}
}
至此可以解答Fragment如何被添加到Activity中的。通过FragmentTransaction#add(id,fragment)并且commit后。经过一系列调用最终调用到FragmentManager#moveToState,在moveToState根据当前Fragment状态来调用Fragment一系列生命周期方法,在Fragment#performCreateView会调用Fragment#onCreateView,并将获取的View添加到add指定的id中。同时也知道了onCreateView中container参数其实就是add指定id的ViewGroup。而这里知道add原理后,其实hide也就是将Fragment中的View GONE掉。
2.FragmentTransaction的add和replace区别?
add刚才分析过了,就是将Fragment中的View添加到add指定的id的ViewGroup中并执行一系列Fragment生命周期方法。那么replace要分情况。
- 如果当前Activity同一个id没有不存Fragment,replace操作和add操作一样。
- 如果当前Activity同一个id存在Fragment,replace传递的Fragment实例和已存在的Fragment实例一样,replace无效果
- 如果当前Activity同一个id存在Fragment,replace传递的Fragment实例和已存在的Fragment实例不一样,删除旧的fragment,添加新的fragment
BackStackRecord#expandOps
Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
for (int opNum = 0; opNum < mOps.size(); opNum++) {
final Op op = mOps.get(opNum);
switch (op.cmd) {
case OP_REMOVE:
case OP_DETACH: {
added.remove(op.fragment);
}
case OP_REPLACE: {
final Fragment f = op.fragment;
final int containerId = f.mContainerId;
boolean alreadyAdded = false;
//如果当前没有Fragment添加到Activity中,added为空
for (int i = added.size() - 1; i >= 0; i--) {
//如果当前已有Fragment添加到Activity中。
final Fragment old = added.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
//如果replace的是同一个Fragment
alreadyAdded = true;
} else {
//不是同一Fragment,删除旧的Fragment
final Op removeOp = new Op(OP_REMOVE, old);
removeOp.enterAnim = op.enterAnim;
removeOp.popEnterAnim = op.popEnterAnim;
removeOp.exitAnim = op.exitAnim;
removeOp.popExitAnim = op.popExitAnim;
mOps.add(opNum, removeOp);
added.remove(old);
opNum++;
}
}
}
if (alreadyAdded) {
mOps.remove(opNum);
opNum--;
} else {
//当前Activity中同一个id没有添加Fragment或者同一个id存在Fragment,但replace传递fragment和已有的不是同一个实例,将操作类型replace修改为add
op.cmd = OP_ADD;
added.add(f);
}
}
break;
}
}
return oldPrimaryNav;
}
那么知道add和replace区别后,也就知道add和replace对Fragment生命周期影响
-
如果当前Activity同一个id没有不存Fragment,replace操作和add操作一样。
即执行两者操作生命周期变化:onAttach->onCreate->onCreateView->onActivityCreated->onStart-onResume,
Fragment所依附的Activity销毁时,执行onPause->onStop->onDestoryView->onDestory->onDetach
-
如果当前Activity同一个id存在Fragment,replace传递的Fragment实例和已存在的Fragment实例一样,replace无效果,这点从上面源码中可以看出
-
如果当前Activity同一个id存在Fragment,replace传递的Fragment实例和已存在的Fragment实例不一样,删除旧的Fragment,添加新的Fragment,这点从上面代码中也可以看出来。
旧的Fragment执行 onPause->onStop->onDestoryView->onDestory->onDetach
新的Fragment执行 onAttach->onCreate->onCreateView->onActivityCreated->onStart-onResume
3.Activity生命周期变化如何通知到Fragment的?
Activity中通知Fragment是在FragmentActivity中各个生命周期方法内通过FragmentController#dispatchxxx方法。 例如FragmentActivity#onPause
//FragmentActivity#onPause
protected void onPause() {
super.onPause();
...
mFragments.dispatchPause();
}
//FragmentController#dispatchPause()
public void dispatchPause() {
mHost.mFragmentManager.dispatchPause();
}
//FragmentManager#dispatchPause()
public void dispatchPause() {
dispatchStateChange(Fragment.STARTED);
}
//FragmentManager#dispatchStateChange()
private void dispatchStateChange(int nextState) {
try {
mExecutingActions = true;
moveToState(nextState, false);
} finally {
mExecutingActions = false;
}
execPendingActions();
}
最终调用moveToState(nextState,false),前面分析过两个参数的moveToState会调用五个参数的moveToState。在五个参数的moveToState完成生命周期的分发。
4.Fragment中状态保存与恢复
都知道Activity中状态保存和恢复可以使用 onSaveInstanceState 和 onCreate 或者 onRestoreInstanceState。Fragment中状态保存也用到onSaveInstanceState,但并没有提供 onRestoreInstanceState 。状态恢复可以在Fragment中onCreate,onViewCreated,onActivityCreated任意一个。
4.1Fragment状态保存触发时机
FragmentActivity#onSaveInstanceState最终会调用Fragment#onSaveInstanceState
FragmentActivity#onSaveInstanceState
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Parcelable p = mFragments.saveAllState();
//这里的p实际是FragmentManagerState
if (p != null) {
//存储Fragment状态
outState.putParcelable(FRAGMENTS_TAG, p);
}
}
整个调用链如下:
- FragmentActivity#onSaveInstanceState
- FragmentController#saveAllState
- FragmentManager#saveAllState
- FragmentManager#saveFragmentBasicState
- Fragment#performSaveInstanceState
- Fragment#onSaveInstanceState
整个调用链关于Fragment自身状态和FragmentManager中保存的关于Fragment数据以及开发者在重写Fragment#onSaveInstanceState的数据被保存在FragmentManagerState并返回。其中FragmentManagerState实现了Parcelable
4.2Fragment状态恢复触发时机
当屏幕旋转,FragmentActivity重建,系统先反射创建新的Fragment并从FragmentManagerState中取出之前保存的数据并赋值给新的Fragment,然后执行新Fragment的onAttach...一系列声明周期方法。并将保存的数据传递给Fragmeng的onCreate,onViewCreated,onActivityCreated。
4.2.1Fragment反射创建
FragmentActivity#onCreate FragmentController#restoreAllState FragmentManager#restoreAllState FragmentState#instantiate FragmentContainer#instantiate Fragment#instantiate
当屏幕旋转FragmentActivity重建,从FragmentActivity#onCreate参数bundle取出之前存储的FragmentManagerState并依次调用FragmentController#restoreAllState...,最后反射创建Fragment并从FragmentManagerState中取出保存的数据并赋值给新创建的Fragment。最后将该Fragment保存到FragmentManager#mActive和mAdd中。
这里挑选创建并恢复Fragment代码片段
//FragmentState#instantiate
public Fragment instantiate(FragmentHostCallback host, FragmentContainer container,
Fragment parent, FragmentManagerNonConfig childNonConfig,
ViewModelStore viewModelStore) {
if (mInstance == null) {
final Context context = host.getContext();
if (mArguments != null) {
mArguments.setClassLoader(context.getClassLoader());
}
if (container != null) {
//反射创建Fragment
mInstance = container.instantiate(context, mClassName, mArguments);
} else {
mInstance = Fragment.instantiate(context, mClassName, mArguments);
}
if (mSavedFragmentState != null) {
//mSavedFragmentState为bundle对象,这里恢复bundle对象,该对象中保存着Fragment中View状态以及自定义保存的数据。
mSavedFragmentState.setClassLoader(context.getClassLoader());
mInstance.mSavedFragmentState = mSavedFragmentState;
}
mInstance.setIndex(mIndex, parent);
mInstance.mFromLayout = mFromLayout;
mInstance.mRestored = true;
mInstance.mFragmentId = mFragmentId;
mInstance.mContainerId = mContainerId;
mInstance.mTag = mTag;
mInstance.mRetainInstance = mRetainInstance;
mInstance.mDetached = mDetached;
mInstance.mHidden = mHidden;
mInstance.mFragmentManager = host.mFragmentManager;
if (FragmentManagerImpl.DEBUG) {
Log.v(FragmentManagerImpl.TAG, "Instantiated fragment " + mInstance);
}
}
mInstance.mChildNonConfig = childNonConfig;
mInstance.mViewModelStore = viewModelStore;
return mInstance;
}
从上面代码可知为什么在Activity中创建Fragment如果需要传递数据,建议使用setArguments。为了就是在Fragment重建时恢复传递的数据。使用其他方式会导致数据的丢失。
4.2.2 恢复数据
恢复数据调用堆栈
- FragmentActivity#onCreate
- FragmentController#dispatchCreate
- FragmentManager#dispatchCreate
- FragmentManager#moveToState//两个参数的moveToState
- FragmentManager#moveToState//五个参数的moveToState
这里挑选Fragment#onCreate恢复数据代码片段
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
switch (f.mState) {
case Fragment.INITIALIZING:
...
if (f.mSavedFragmentState != null) {
//一系列恢复操作
}
f.onAttach(mHost.getContext());
f.performCreate(f.mSavedFragmentState);
}
...
}
从Frgament反射创建与恢复数据可知f.mSavedFragmentState不为空并且保存的是View中的状态以及自定义保存数据。这里调用performCreate->onCreate并将mSaveFragmentState传递给onCreate,在onCreate中根据传递的mSaveFragmentState(bundle对象)来获取保存的数据。
5.setRetainInstance()的作用是什么?
如果Fragment设置setRetainInstance(true),那么它所依附的Activity重建后该Fragment不会重新销毁并创建。也就是重建后和重建前的实例一样。 setRetainInstance(true) 非正常销毁时不会走Fragment#onDestory() 非正常创建时不会走Fragment#onCreate() 前提是在创建Fragment需要在FragmentManager中根据TAG查找Fragment是否为空,为空则创建添加。
根据设置setRetainInstance(true),可以应用到将Activity中的数据保存到Fragment中,以完成屏幕旋转,以及其他重建Activity时的数据恢复操作。
6.FragmentTransaction各种提交操作介绍?
commit();
commit是将事务操作放到主线程消息队列中,所以它并不是同步操作。commit不允许状态丢失,也就是在onSaveInstanceState之后不允许commit操作。(Can not perform this action after onSaveInstanceState)
commitAllowingStateLoss();
和commit操作一样。区别是允许丢失状态。允许在onSaveInstanceState之后操作事务。
commitNow();
同步执行Fragment事务操作,不允许丢失状态。
commitNowAllowingStateLoss();
同步执行Fragment事务操作,允许丢失状态。
7.开发中容易忽视的问题
7.1状态恢复相关
7.1.1 使用FragmentPagerAdapter时,需要考虑宿主Activity重建带来的问题
在activity使用FragmentPagerAdapter时,随手写出如下代码。其实这样写看似没问题,其实隐藏风险。
private val mFragmentList = mutableListOf<Fragment>()
mFragmentList.add(xxx)
mFragmentList.add(xxx)
mFragmentList.add(xxx)
...
view_pager.setAdapter(supportFragmentManager, mFragmentList)
fun <T : Fragment> ViewPager.setAdapter(fragmentManager: FragmentManager, fragmentList: MutableList<T>) {
adapter = object : FragmentPagerAdapter(fragmentManager) {
override fun getItem(position: Int): Fragment {
return fragmentList[position]
}
override fun getCount(): Int {
return fragmentList.size
}
}
}
如果后续通过mFragmentList进行操作,比如刷新第1个位置fragment中的数据。
mFragmentList.get(0).refresh()
那么在activity重建后(屏幕旋转或者后台进程重启)根据mFragmentList去刷新第一个位置的fragment不起作用。具体原因如下:
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) {
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
...
return fragment;
}
在ViewPager加载当前页时,会通过FragmentPagerAdapter调用instantiateItem来加载当前fragment。而当前fragment创建时通过fragmentManager做了一层判断。为空时,才创建,即调用getItem(position)即从mFragmentList中取出fragment。如果不为空直接就复用。
问题就出现在当activity重建时,系统调用activity的onSaveInstanceState()来实现状态的保存,而onSaveInstanceState()中会通过fragmentManager对当前已添加的fragment进行保存。等到系统重建完后在onCreate()中通过fragmentManager来恢复之前保存的fragment。
那么此时即使从新设置了viewPager的adapter。但是instantiateItem()中获取fragment的fragmentManager是同一个。也就是获取到的还是activity重建前的fragment。也就是当前屏幕展示的和mFragmentList中保存的fragment不一致。
解决方案如下: 在每次创建fragment之前判断下。为空则创建,否则不创建。
mFragmentList.apply {
addFragment(this, view_pager, 0) {
//创建fragment实例并返回
}
addFragment(this, view_pager, 1) {
//创建fragment实例并返回
}
}
inline fun <reified T : Fragment> MutableList<T>.addFragment(fragmentActivity: FragmentActivity, viewGroup: ViewGroup, pos: Int, createFragment: () -> T) {
val tag = "android:switcher:" + viewGroup.id + ":" + pos
val fragment: T = fragmentActivity.supportFragmentManager.findFragmentByTag(tag) as? T
?: createFragment()
add(fragment)
}