概述: Fragment从commit到resume状态的过程是?
这一part,我们以activity通过 replace的方案启动一个fragment 做为case,梳理一下 起启动过程 fragment的启动过程本质上是view的加载过程,只不过给view增加了生命周期的能力, 可以将上述的流程图抽象为下面几个步骤
-
new一个事务(图中的BackStackRecord)
-
往事务添加需要执行的 命令(图中replace)
-
提交该事务 (图中commitInternal)
-
将命令打散(expandOps)为一个个的子命令执行。比如 (replace -> remove + add)
-
命令执行过程中,会改变Fragment的状态,作为computeExpectedState函数的入参去计算最终态。
比如 add命令 -> addFragment -> fragment.mAdded = true, fragment.mRemoving = false 。 再computeExpectedState中计算可以得到 最终态是resume。比如 add命令 -> addFragment -> fragment.mAdded = true, fragment.mRemoving = false 。 再computeExpectedState中计算可以得到 最终态是resume。
- 通过moveToExpectedState执行fragment的生命周期, 直到达到最终态Resume.
从提交开始:fragment中各种 命令& commit xxx到底有撒区别
一段典型的fragment初始化代码,这一part
fragmentManager
// new一个事务
.beginTransaction()
// 往事务添加需要执行的 命令
.replace(R.id.frag_entrance_main_container, Test1Fragment.newInstance("1", "2"), "test1")
// 提交
.commit()
两个问题
-
fragment初始化两种命令可执行,add, replace。他们区别是啥?
-
提交多4种方法,他们区别是撒?
如果从activity里启动,两者基本无区别,因为此时replace命令只会解析成 add
如果从【old fragment】里启动兄弟节点【new fragment】,replace会解析(expandOps)成 remove + add。
commitXXX
如上图,fragment有四种commit, 之所以有四种,是基于两个变量即allowStateLoss ,Now
allowStateLoss:表示宿主activity在后台能否改变 fragment的状态,true表示可以改变,false表示不能改变,如果改变了会抛异常
case: activity A在onStop过程中,执行了fragment相关命令,会抛出异常
Now: 表示执行fragment的生命周期是否需要post出去, true表示不用post,false表示需要post
表格如下:
allowStateLoss | Now | 含义 | 使用场景 | |
---|---|---|---|---|
commit | false | false | 无场景 | |
commitAllowingStateLoss | true | false | 多个事务整合在一起提交 | |
CommitNow | false | true | 无场景 | |
commitNowAllowingStateLoss | true | true | 只提交一个事务 |
一般情况下会调用commitAllowingStateLoss 或者 commitNowAllowingStateLoss。
状态计算:Fragment中的命令是如何驱动状态变化的
这里以 replace命令为例,
-
首先replace会解析成两个子命令 add + remove, 其中add是指:add(新增fragment),remove是指:remove(旧fragment)
-
这里我们看一下remove(旧fragment)流程
// BackStackRecord -> excuteOps
void executeOps() {
case OP_ADD:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.addFragment(f);
break;
case OP_REMOVE:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
// 取改变fragment的状态
mManager.removeFragment(f);
break;
}
// FragmentManager -> removeFragment
void removeFragment(@NonNull Fragment fragment) {
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
}
final boolean inactive = !fragment.isInBackStack();
if (!fragment.mDetached || inactive) {
mFragmentStore.removeFragment(fragment);
if (isMenuAvailable(fragment)) {
mNeedMenuInvalidate = true;
}
fragment.mRemoving = true;
setVisibleRemovingFragment(fragment);
}
}
// FragmentStore -> removeFragment
void removeFragment(@NonNull Fragment fragment) {
synchronized (mAdded) {
mAdded.remove(fragment);
}
fragment.mAdded = false;
}
int computeExpectedState() {
// If the FragmentManager is null, disallow changing the state at all
if (mFragment.mFragmentManager == null) {
return mFragment.mState;
}
// added = false
if (!mFragment.mAdded) {
maxState = Math.min(maxState, Fragment.CREATED);
}
SpecialEffectsController.Operation.LifecycleImpact awaitingEffect = null;
if (FragmentManager.USE_STATE_MANAGER && mFragment.mContainer != null) {
SpecialEffectsController controller = SpecialEffectsController.getOrCreateController(
mFragment.mContainer, mFragment.getParentFragmentManager());
awaitingEffect = controller.getAwaitingCompletionLifecycleImpact(this);
}
if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.ADDING) {
// Fragments awaiting their enter effects cannot proceed beyond that state
maxState = Math.min(maxState, Fragment.AWAITING_ENTER_EFFECTS);
} else if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.REMOVING) {
// Fragments that are in the process of being removed shouldn't go below that state
maxState = Math.max(maxState, Fragment.AWAITING_EXIT_EFFECTS);
} else if (mFragment.mRemoving) {
if (mFragment.isInBackStack()) {
// 如果在堆栈里,就只执行 最终态就是CREATED
maxState = Math.min(maxState, Fragment.CREATED);
} else {
maxState = Math.min(maxState, Fragment.INITIALIZING);
}
}
return maxState;
}
-
computeExpectedState 计算出的状态是 Fragment.CREATED 或者Fragment.INITIALIZING
-
当前状态是Resume
-
所以通过moveToExpectState 去将状态扭转到 Fragment.CREATED 或者Fragment.INITIALIZING
状态迁移:fragment为何要区分这么多状态
从源码可以看到fragment状态如下
static final int INITIALIZING = -1; // Not yet attached.
static final int ATTACHED = 0; // Attached to the host.
static final int CREATED = 1; // Created.
static final int VIEW_CREATED = 2; // View Created.
static final int ACTIVITY_CREATED = 4; // Fully created, not started.
static final int STARTED = 5; // Created and started, not resumed.
static final int RESUMED = 7; // Created started and resumed.
可以用分层的思想思考下,为什么要分这么多状态,每种状态做了什么。下图是状态 和 事件的关系:
计算当前状态S1, 需要扭转的状态S2。 如果是升级即S2 > S1则走 正向状态扭转,如果是降级,则走逆向状态扭转
onAttach和onDetach是逆操作,同理 onCreate和onDestory也互为可逆。所以之前正向事件做了什么基本就知道了逆向事件做了什么了
- onAttach: 宿主对象赋值
- onCreate: 对齐activity,并在内部恢复一些属性
- onViewCreate: 加载视图
- onStart: 对齐activity
- onResume: fragment进入运行态且对齐activity onresume
纵向管理:Fragment是如何管理子fragment的
通过FragmentManager管理
Fragment {
// 访问父节点,父节点只有一个
Fragment mParentFragment
// 用于访问 兄弟fragment, 多个
FragmentManager parentFragmentManager
// 用于访问当前framgent的子fragment, 多个
FragmentManager childFragmentManager
}
FragmentManager {
// 可以理解为 List<Fragment>
FragmentStore fragmentStore
}
数据结构 和如下gpt回答的类似
横向管理:Fragment如何管理兄弟节点的
纵向fragment通过树结构来管理,横向兄弟fragment之间关系 用堆栈来管理
如上图:一个BackStackRecord表示一个事务,一个事务由多个命令构成,当回滚事务时(即调用popBackStack),做逆操作即可。上图可拆分成如下步骤
-
push一个BackStackRecord(add) -> add fragmentA
-
push 一个 BackStackRecord(Replace) -> remove fragmentA + add fragmentB
开始回滚
-
fragmentB popBack -> add fragmentA + remove FragmentB
-
fragmentA popBack -> remove FragmentA
popBackStack源码中,会执行executePopOps 如下
Fragment中是如何处理状态销毁和恢复的?
核心思路:销毁时存储元数据,恢复时,通过元数据 对framgment进行视图重建。然后通过业务数据绑定视图
存储的元数据结构为 FragmentState
final String mClassName;
final String mWho;
final boolean mFromLayout;
final int mFragmentId;
final int mContainerId;
final String mTag;
final boolean mRetainInstance;
final boolean mRemoving;
final boolean mDetached;
final Bundle mArguments;
final boolean mHidden;
final int mMaxLifecycleState;
下图是存储FragmentState流程
下图是fragment的恢复流程:
-
屏幕发生了旋转,fragment会通过反射重新实例化。这个过程中会调用 fragment的无参构造函数。
-
makeActive 恢复FrammentStore的FragmentStateManager。 restoreAddedFragments恢复FragmentStore中的Fragment
-
这个过程会依赖activity的事件分发
源码分析
Attach
activity的host赋值在, FragmentActivity 构造函数内部调用init
private void init() {
addOnContextAvailableListener(new OnContextAvailableListener() {
@Override
public void onContextAvailable(@NonNull Context context) {
mFragments.attachHost(null /*parent*/);
Bundle savedInstanceState = getSavedStateRegistry()
.consumeRestoredStateForKey(FRAGMENTS_TAG);
if (savedInstanceState != null) {
Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
mFragments.restoreSaveState(p);
}
}
});
}
fragment类型的host赋值在 父fragment performAttach的时候
void performAttach() {
for (OnPreAttachedListener listener: mOnPreAttachedListeners) {
listener.onPreAttached();
}
mOnPreAttachedListeners.clear();
mChildFragmentManager.attachController(mHost, createFragmentContainer(), this);
mState = ATTACHED;
mCalled = false;
onAttach(mHost.getContext());
if (!mCalled) {
throw new SuperNotCalledException("Fragment " + this
+ " did not call through to super.onAttach()");
}
mFragmentManager.dispatchOnAttachFragment(this);
mChildFragmentManager.dispatchAttach();
}
expandOPs
Fragment expandOps(ArrayList<Fragment> added, Fragment oldPrimaryNav) {
for (int opNum = 0; opNum < mOps.size(); opNum++) {
final Op op = mOps.get(opNum);
switch (op.mCmd) {
case OP_ADD:
case OP_ATTACH:
added.add(op.mFragment);
break;
case OP_REMOVE:
case OP_DETACH: {
added.remove(op.mFragment);
if (op.mFragment == oldPrimaryNav) {
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, op.mFragment));
opNum++;
oldPrimaryNav = null;
}
}
break;
case OP_REPLACE: {
final Fragment f = op.mFragment;
final int containerId = f.mContainerId;
boolean alreadyAdded = false;
for (int i = added.size() - 1; i >= 0; i--) {
final Fragment old = added.get(i);
if (old.mContainerId == containerId) {
if (old == f) {
alreadyAdded = true;
} else {
// This is duplicated from above since we only make
// a single pass for expanding ops. Unset any outgoing primary nav.
if (old == oldPrimaryNav) {
mOps.add(opNum, new Op(OP_UNSET_PRIMARY_NAV, old));
opNum++;
oldPrimaryNav = null;
}
final Op removeOp = new Op(OP_REMOVE, old);
removeOp.mEnterAnim = op.mEnterAnim;
removeOp.mPopEnterAnim = op.mPopEnterAnim;
removeOp.mExitAnim = op.mExitAnim;
removeOp.mPopExitAnim = op.mPopExitAnim;
// old fragment和new fragment containerid一致,replace命令会先解析成remove + add
mOps.add(opNum, removeOp);
added.remove(old);
opNum++;
}
}
}
if (alreadyAdded) {
mOps.remove(opNum);
opNum--;
} else {
op.mCmd = OP_ADD;
added.add(f);
}
}
break;
}
}
return oldPrimaryNav;
}
状态保存与恢复
FragmentManager.java
Parcelable saveAllState() {
// Build list of currently added fragments.
// 保存该宿主中所有的 添加过的 fragment
ArrayList<String> added = mFragmentStore.saveAddedFragments();
// Now save back stack.
// 保存堆栈
BackStackState[] backStack = null;
if (mBackStack != null) {
int size = mBackStack.size();
if (size > 0) {
backStack = new BackStackState[size];
for (int i = 0; i < size; i++) {
backStack[i] = new BackStackState(mBackStack.get(i));
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "saveAllState: adding back stack #" + i
+ ": " + mBackStack.get(i));
}
}
}
}
FragmentManagerState fms = new FragmentManagerState();
fms.mActive = active;
fms.mAdded = added;
fms.mBackStack = backStack;
fms.mBackStackIndex = mBackStackIndex.get();
if (mPrimaryNav != null) {
fms.mPrimaryNavActiveWho = mPrimaryNav.mWho;
}
// 参数
fms.mResultKeys.addAll(mResults.keySet());
fms.mResults.addAll(mResults.values());
fms.mLaunchedFragments = new ArrayList<>(mLaunchedFragments);
return fms;
}
void restoreSaveState(@Nullable Parcelable state) {
// If there is no saved state at all, then there's nothing else to do
if (state == null) return;
FragmentManagerState fms = (FragmentManagerState) state;
if (fms.mActive == null) return;
// 可以理解为 恢复fragment需要的元数据
for (FragmentState fs : fms.mActive) {
if (fs != null) {
FragmentStateManager fragmentStateManager;
// 初始化 fragment 及 fragmentStateManager
fragmentStateManager = new FragmentStateManager(mLifecycleCallbacksDispatcher,
mFragmentStore, mHost.getContext().getClassLoader(),
getFragmentFactory(), fs);
Fragment f = fragmentStateManager.getFragment();
f.mFragmentManager = this;
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "restoreSaveState: active (" + f.mWho + "): " + f);
}
fragmentStateManager.restoreState(mHost.getContext().getClassLoader());
mFragmentStore.makeActive(fragmentStateManager);
// Catch the FragmentStateManager up to our current state
// In almost all cases, this is Fragment.INITIALIZING, but just in
// case a FragmentController does something...unique, let's do this anyways.
fragmentStateManager.setFragmentManagerState(mCurState);
}
}
// 通过FragmentState. 恢复 store里的added framgent列表
mFragmentStore.restoreAddedFragments(fms.mAdded);
// Build the back stack.
if (fms.mBackStack != null) {
mBackStack = new ArrayList<>(fms.mBackStack.length);
for (int i = 0; i < fms.mBackStack.length; i++) {
BackStackRecord bse = fms.mBackStack[i].instantiate(this);
if (isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "restoreAllState: back stack #" + i
+ " (index " + bse.mIndex + "): " + bse);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
bse.dump(" ", pw, false);
pw.close();
}
mBackStack.add(bse);
}
} else {
mBackStack = null;
}
mBackStackIndex.set(fms.mBackStackIndex);
if (fms.mPrimaryNavActiveWho != null) {
mPrimaryNav = findActiveFragment(fms.mPrimaryNavActiveWho);
dispatchParentPrimaryNavigationFragmentChanged(mPrimaryNav);
}
ArrayList<String> savedResultKeys = fms.mResultKeys;
if (savedResultKeys != null) {
for (int i = 0; i < savedResultKeys.size(); i++) {
Bundle savedResult = fms.mResults.get(i);
savedResult.setClassLoader(mHost.getContext().getClassLoader());
mResults.put(savedResultKeys.get(i), savedResult);
}
}
mLaunchedFragments = new ArrayDeque<>(fms.mLaunchedFragments);
}
fragment初始化
FragmentStateManager.java -> instantiate
FragmentStateManager(@NonNull FragmentLifecycleCallbacksDispatcher dispatcher,
@NonNull FragmentStore fragmentStore,
@NonNull ClassLoader classLoader,
@NonNull FragmentFactory fragmentFactory,
@NonNull FragmentState fs) {
mDispatcher = dispatcher;
mFragmentStore = fragmentStore;
mFragment = fragmentFactory.instantiate(classLoader, fs.mClassName);
if (fs.mArguments != null) {
fs.mArguments.setClassLoader(classLoader);
}
mFragment.setArguments(fs.mArguments);
mFragment.mWho = fs.mWho;
mFragment.mFromLayout = fs.mFromLayout;
mFragment.mRestored = true;
mFragment.mFragmentId = fs.mFragmentId;
mFragment.mContainerId = fs.mContainerId;
mFragment.mTag = fs.mTag;
mFragment.mRetainInstance = fs.mRetainInstance;
mFragment.mRemoving = fs.mRemoving;
mFragment.mDetached = fs.mDetached;
mFragment.mHidden = fs.mHidden;
mFragment.mMaxState = Lifecycle.State.values()[fs.mMaxLifecycleState];
if (fs.mSavedFragmentState != null) {
mFragment.mSavedFragmentState = fs.mSavedFragmentState;
} else {
// When restoring a Fragment, always ensure we have a
// non-null Bundle so that developers have a signal for
// when the Fragment is being restored
mFragment.mSavedFragmentState = new Bundle();
}
if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
Log.v(TAG, "Instantiated fragment " + mFragment);
}
}
计算期待的状态
int computeExpectedState() {
// If the FragmentManager is null, disallow changing the state at all
if (mFragment.mFragmentManager == null) {
return mFragment.mState;
}
// Assume the Fragment can go as high as the FragmentManager's state
int maxState = mFragmentManagerState;
// Don't allow the Fragment to go above its max lifecycle state
switch (mFragment.mMaxState) {
case RESUMED:
// maxState can't go any higher than RESUMED, so there's nothing to do here
break;
case STARTED:
maxState = Math.min(maxState, Fragment.STARTED);
break;
case CREATED:
maxState = Math.min(maxState, Fragment.CREATED);
break;
case INITIALIZED:
maxState = Math.min(maxState, Fragment.ATTACHED);
break;
default:
maxState = Math.min(maxState, Fragment.INITIALIZING);
}
// For fragments that are created from a layout using the <fragment> tag (mFromLayout)
if (mFragment.mFromLayout) {
if (mFragment.mInLayout) {
// Move them immediately to VIEW_CREATED when they are
// actually added to the layout (mInLayout).
maxState = Math.max(mFragmentManagerState, Fragment.VIEW_CREATED);
// But don't move to higher than VIEW_CREATED until the view is added to its parent
// and the LayoutInflater call has returned
if (mFragment.mView != null && mFragment.mView.getParent() == null) {
maxState = Math.min(maxState, Fragment.VIEW_CREATED);
}
} else {
if (mFragmentManagerState < Fragment.ACTIVITY_CREATED) {
// But while they are not in the layout, don't allow their
// state to progress upward until the FragmentManager state
// is at least ACTIVITY_CREATED. This ensures they get the onInflate()
// callback before being attached or created.
maxState = Math.min(maxState, mFragment.mState);
} else {
// Once the FragmentManager state is at least ACTIVITY_CREATED
// their state can progress up to CREATED as we assume that
// they are not ever going to be in layout
maxState = Math.min(maxState, Fragment.CREATED);
}
}
}
// Fragments that are not currently added will sit in the CREATED state.
if (!mFragment.mAdded) {
// remove了fragment,需要状态降级
maxState = Math.min(maxState, Fragment.CREATED);
}
SpecialEffectsController.Operation.LifecycleImpact awaitingEffect = null;
if (FragmentManager.USE_STATE_MANAGER && mFragment.mContainer != null) {
SpecialEffectsController controller = SpecialEffectsController.getOrCreateController(
mFragment.mContainer, mFragment.getParentFragmentManager());
awaitingEffect = controller.getAwaitingCompletionLifecycleImpact(this);
}
if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.ADDING) {
// Fragments awaiting their enter effects cannot proceed beyond that state
maxState = Math.min(maxState, Fragment.AWAITING_ENTER_EFFECTS);
} else if (awaitingEffect == SpecialEffectsController.Operation.LifecycleImpact.REMOVING) {
// Fragments that are in the process of being removed shouldn't go below that state
maxState = Math.max(maxState, Fragment.AWAITING_EXIT_EFFECTS);
} else if (mFragment.mRemoving) {
if (mFragment.isInBackStack()) {
// fragment放堆栈里,最低状态就是create
// Fragments on the back stack shouldn't go higher than CREATED
maxState = Math.min(maxState, Fragment.CREATED);
} else {
// 没有
// While removing a fragment, we always move to INITIALIZING
maxState = Math.min(maxState, Fragment.INITIALIZING);
}
}
// Defer start if requested; don't allow it to move to STARTED or higher
// if it's not already started.
if (mFragment.mDeferStart && mFragment.mState < Fragment.STARTED) {
maxState = Math.min(maxState, Fragment.ACTIVITY_CREATED);
}
if (FragmentManager.isLoggingEnabled(Log.VERBOSE)) {
Log.v(FragmentManager.TAG, "computeExpectedState() of " + maxState + " for "
+ mFragment);
}
return maxState;
}
fragment中的命令
从下面函数中能窥探 fragment的命令及对应执行的代码:
void executeOps() {
final int numOps = mOps.size();
for (int opNum = 0; opNum < numOps; opNum++) {
final Op op = mOps.get(opNum);
final Fragment f = op.mFragment;
if (f != null) {
f.setPopDirection(false);
f.setNextTransition(mTransition);
f.setSharedElementNames(mSharedElementSourceNames, mSharedElementTargetNames);
}
switch (op.mCmd) {
case OP_ADD:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.addFragment(f);
break;
case OP_REMOVE:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.removeFragment(f);
break;
case OP_HIDE:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.hideFragment(f);
break;
case OP_SHOW:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.showFragment(f);
break;
case OP_DETACH:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.detachFragment(f);
break;
case OP_ATTACH:
f.setAnimations(op.mEnterAnim, op.mExitAnim, op.mPopEnterAnim, op.mPopExitAnim);
mManager.setExitAnimationOrder(f, false);
mManager.attachFragment(f);
break;
case OP_SET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(f);
break;
case OP_UNSET_PRIMARY_NAV:
mManager.setPrimaryNavigationFragment(null);
break;
case OP_SET_MAX_LIFECYCLE:
mManager.setMaxLifecycle(f, op.mCurrentMaxState);
break;
default:
throw new IllegalArgumentException("Unknown cmd: " + op.mCmd);
}
if (!mReorderingAllowed && op.mCmd != OP_ADD && f != null) {
if (!FragmentManager.USE_STATE_MANAGER) {
mManager.moveFragmentToExpectedState(f);
}
}
}
if (!mReorderingAllowed && !FragmentManager.USE_STATE_MANAGER) {
// Added fragments are added at the end to comply with prior behavior.
mManager.moveToState(mManager.mCurState, true);
}
}