Activity 生命周期。Fragment的生命周期会跟随Activity的生命周期所以需要知道Activity的生命周期。
Activity 中onSaveInstanceState 和onRestoreInstanceState(即Activity的备忘录模式)。Activity 在某种情况下会备份一些信息,包括管理的Dialog、里面的Fragment、Activity 对应的Window 中对应的View 信息等。Fragment 也需要备份一些自身的信息。所以这一块也需要了解一点好。
Activity 任务栈。TaskRecord.java
Fragment 可以保存自己的栈信息。在FramgentManagerImpl 中维护了一个Fragment 的栈信息ArrayList
每次remove 的时候都是remove 掉最后一个。Fragment 默认是没有保存栈信息的。
// FragmentManagerImpl.java
addBackStackState(BackStackRecord state)
popBackStack() // 有一系列的方法,最终都是会调用popBackStackState()
一般的操作是这样的getSupportFragmentManager().beginTransaction().add/replace/remove/hide/show/detach/attach.commit()
。那么这样的操作是如何将一个View(一般写在Activity 对应的xml 中) 和一个Fragment 联系在一起的呢?
首先需要了解一个问题,FragmentManagerImpl 中保存了一个状态信息mCurState
(Activity 生命周期会对其影响) 同时Fragment 中也保存了一个状态信息mState
。FragmentManagerImpl 中保存的是当前的状态信息,而不同的Fragment中则保存的各自的状态信息,最终的结果是将Fragment 的状态变成FragmentManagerImpl 的状态。
Fragment 的几种不同状态,默认是INITIALIZING
// Fragment.java
static final int INITIALIZING = 0; // Not yet created.
static final int CREATED = 1; // Created.
static final int ACTIVITY_CREATED = 2; // The activity has finished its creation.
static final int STOPPED = 3; // Fully created, not started.
static final int STARTED = 4; // Created and started, not resumed.
static final int RESUMED = 5; // Created started and resumed.
介绍其中的几个流程,代码是基于support-v4-23.1.1
的。
1.获取FragmentTransaction。即BackStackRecord
。
@Override
public FragmentTransaction beginTransaction() {
return new BackStackRecord(this);
}
2.add 操作,这里使用了某一个add 方法(有多个),很简单只是做了一个doAddOp 操作。
// BackStackRecord.java
public FragmentTransaction add(int containerViewId, Fragment fragment) {
doAddOp(containerViewId, fragment, null, OP_ADD);
return this;
}
3.doAddOp 操作。
// BackStackRecord.java
private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
fragment.mFragmentManager = mManager;
if (tag != null) {
if (fragment.mTag != null && !tag.equals(fragment.mTag)) {
throw new IllegalStateException("Can't change tag of fragment "
+ fragment + ": was " + fragment.mTag
+ " now " + tag);
}
fragment.mTag = tag;
}
if (containerViewId != 0) {
if (fragment.mFragmentId != 0 && fragment.mFragmentId != containerViewId) {
throw new IllegalStateException("Can't change container ID of fragment "
+ fragment + ": was " + fragment.mFragmentId
+ " now " + containerViewId);
}
fragment.mContainerId = fragment.mFragmentId = containerViewId;
}
Op op = new Op();
op.cmd = opcmd;
op.fragment = fragment;
addOp(op); // Op 相当于是一个双向列表,这里是在列表中加入一个一些Op 对象。
}
4.commit 操作会执行到commitInternal,直接看commitInternal。
// BackStackRecord.java
int commitInternal(boolean allowStateLoss) {
if (mCommitted) throw new IllegalStateException("commit already called");
if (FragmentManagerImpl.DEBUG) {
Log.v(TAG, "Commit: " + this);
LogWriter logw = new LogWriter(TAG);
PrintWriter pw = new PrintWriter(logw);
dump(" ", null, pw, null);
}
mCommitted = true;
if (mAddToBackStack) {
mIndex = mManager.allocBackStackIndex(this);
} else {
mIndex = -1;
}
mManager.enqueueAction(this, allowStateLoss); // 第一个参数是this,也就是BackStackRecord 的对象。
return mIndex;
}
5.enqueueAction 操作。
// FragmentManagerImpl.java
public void enqueueAction(Runnable action, boolean allowStateLoss) {
if (!allowStateLoss) {
checkStateLoss();
}
synchronized (this) {
if (mDestroyed || mHost == null) {
throw new IllegalStateException("Activity has been destroyed");
}
if (mPendingActions == null) {
mPendingActions = new ArrayList();
}
// 将action(BackStackRecord) 加入到mPendingActions
mPendingActions.add(action);
if (mPendingActions.size() == 1) {
mHost.getHandler().removeCallbacks(mExecCommit);
mHost.getHandler().post(mExecCommit); //
}
}
}
6.执行mExecCommit 中的run 方法,就是execPendingActions 方法。
// FragmentManagerImpl.java
public boolean execPendingActions() {
if (mExecutingActions) {
throw new IllegalStateException("Recursive entry to executePendingTransactions");
}
if (Looper.myLooper() != mHost.getHandler().getLooper()) {
throw new IllegalStateException("Must be called from main thread of process");
}
boolean didSomething = false;
while (true) {
int numActions;
synchronized (this) {
if (mPendingActions == null || mPendingActions.size() == 0) {
break;
}
numActions = mPendingActions.size();
if (mTmpActions == null || mTmpActions.length < numActions) {
mTmpActions = new Runnable[numActions];
}
// 这里的 mPendingActions 就是上面的mPendingActions,通过toArray 方法转化成了一个零时数组
mPendingActions.toArray(mTmpActions);
mPendingActions.clear();
mHost.getHandler().removeCallbacks(mExecCommit);
}
mExecutingActions = true;
for (int i=0; i// 执行零时数组的run 方法,其实就是BackStackRecord 的run 方法。
mTmpActions[i].run();
mTmpActions[i] = null;
}
mExecutingActions = false;
didSomething = true;
}
if (mHavePendingDeferredStart) {
boolean loadersRunning = false;
for (int i=0; iif (f != null && f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
if (!loadersRunning) {
mHavePendingDeferredStart = false;
startPendingDeferredFragments();
}
}
return didSomething;
}
7.执行BackStateRecord 的run 方法。
// BackStackRecord.java
public void run() {
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Run: " + this);
if (mAddToBackStack) {
if (mIndex < 0) {
throw new IllegalStateException("addToBackStack() called after commit()");
}
}
bumpBackStackNesting(1);
TransitionState state = null;
SparseArray firstOutFragments = null;
SparseArray lastInFragments = null;
if (SUPPORTS_TRANSITIONS) { // 支持过度动画的一些操作
firstOutFragments = new SparseArray();
lastInFragments = new SparseArray();
calculateFragments(firstOutFragments, lastInFragments);
state = beginTransition(firstOutFragments, lastInFragments, false);
}
int transitionStyle = state != null ? 0 : mTransitionStyle;
int transition = state != null ? 0 : mTransition;
Op op = mHead;
while (op != null) {
int enterAnim = state != null ? 0 : op.enterAnim;
int exitAnim = state != null ? 0 : op.exitAnim;
switch (op.cmd) {
case OP_ADD: {
// 最终执行到的地方,会执行addFragment 操作
Fragment f = op.fragment;
f.mNextAnim = enterAnim;
mManager.addFragment(f, false);
} break;
... // 省略很多代码
default: {
throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
}
}
op = op.next;
}
// 执行完相应的操作以后会执行moveToState 操作
mManager.moveToState(mManager.mCurState, transition, transitionStyle, true);
if (mAddToBackStack) {
mManager.addBackStackState(this);
}
}
8.上面注释已经有分析需要的做操作,首先是FragmentManageImpl 的addFragment 操作。
// FragmentManagerImpl.java
public void addFragment(Fragment fragment, boolean moveToStateNow) {
if (mAdded == null) {
mAdded = new ArrayList();
}
if (DEBUG) Log.v(TAG, "add: " + fragment);
// 将Fragment 置为Active 状态。
makeActive(fragment);
if (!fragment.mDetached) {
if (mAdded.contains(fragment)) {
throw new IllegalStateException("Fragment already added: " + fragment);
}
// 将该Fragment 加入到mAdded List中
mAdded.add(fragment);
fragment.mAdded = true;
fragment.mRemoving = false;
if (fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
if (moveToStateNow) { // 这里一般是false
moveToState(fragment);
}
}
}
执行FragmentManageImpl 的moveToState。
// FragmentManagerImpl.java
void moveToState(int newState, int transit, int transitStyle, boolean always) {
if (mHost == null && newState != Fragment.INITIALIZING) {
throw new IllegalStateException("No host");
}
if (!always && mCurState == newState) {
return;
}
mCurState = newState;
if (mActive != null) {
boolean loadersRunning = false;
for (int i=0; iif (f != null) {
// 执行下一步moveToState,注意这里是active 的Fragment 才会继续向下执行的
moveToState(f, newState, transit, transitStyle, false);
if (f.mLoaderManager != null) {
loadersRunning |= f.mLoaderManager.hasRunningLoaders();
}
}
}
... // 省略代码
}
}
执行FragmentManageImpl 下一步的moveToState(存在Fragment 的时候才会执行)。这段代码里面一个重要的逻辑是Fragment 的状态和FragmentManagerImpl 状态的比较,FragmentManagerImpl 的状态是Fragment 将要到达的状态。
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
if (f.mRemoving && newState > f.mState) {
newState = f.mState;
}
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
if (f.mState < newState) {
// Fragment 的状态和FragmentManagerImpl 的状态比较,上面有解释。
if (f.mFromLayout && !f.mInLayout) {
return;
}
if (f.mAnimatingAway != null) {
f.mAnimatingAway = null;
moveToState(f, f.mStateAfterAnimating, 0, 0, true);
}
// 注意case 里面没有break
switch (f.mState) {
case Fragment.INITIALIZING:
if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
if (f.mSavedFragmentState != null) {
f.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
FragmentManagerImpl.VIEW_STATE_TAG);
f.mTarget = getFragment(f.mSavedFragmentState,
FragmentManagerImpl.TARGET_STATE_TAG);
if (f.mTarget != null) {
f.mTargetRequestCode = f.mSavedFragmentState.getInt(
FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
}
f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
if (!f.mUserVisibleHint) {
f.mDeferStart = true;
if (newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
}
}
f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
f.mCalled = false;
// 执行Fragment 的onAttach 方法
f.onAttach(mHost.getContext());
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
// 最终毁掉到Activity 的onAtachFragment
mHost.onAttachFragment(f);
}
if (!f.mRetaining) {
// 最终执行Fragment 的onCreate
f.performCreate(f.mSavedFragmentState);
}
f.mRetaining = false;
if (f.mFromLayout) {
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), null, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
if (Build.VERSION.SDK_INT >= 11) {
ViewCompat.setSaveFromParentEnabled(f.mView, false);
} else {
f.mView = NoSaveStateFrameLayout.wrap(f.mView);
}
if (f.mHidden) f.mView.setVisibility(View.GONE);
f.onViewCreated(f.mView, f.mSavedFragmentState);
} else {
f.mInnerView = null;
}
}
case Fragment.CREATED:
if (newState > Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
// f.mContainerId 就是通过设置BackStackRecord.add() 时候传过来的id,即container 就是xml 文件中定义的View。而onFindViewById 最终会调用到Activity 的findViewById。
container = (ViewGroup)mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
throwException(new IllegalArgumentException(
"No view found for id 0x"
+ Integer.toHexString(f.mContainerId) + " ("
+ f.getResources().getResourceName(f.mContainerId)
+ ") for fragment " + f));
}
}
f.mContainer = container;
// 最终会调用到Fragment 的onCreateView()
f.mView = f.performCreateView(f.getLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
if (Build.VERSION.SDK_INT >= 11) {
ViewCompat.setSaveFromParentEnabled(f.mView, false);
} else {
f.mView = NoSaveStateFrameLayout.wrap(f.mView);
}
if (container != null) {
Animation anim = loadAnimation(f, transit, true,
transitionStyle);
if (anim != null) {
setHWLayerAnimListenerIfAlpha(f.mView, anim);
f.mView.startAnimation(anim);
}
// container 将Fragment onCreateView 得到的View 加进去,这样相当于建立了Fragment 与View 之间的联系。
container.addView(f.mView);
}
if (f.mHidden) f.mView.setVisibility(View.GONE);
// Fragment 的onViewCreated 回调。
f.onViewCreated(f.mView, f.mSavedFragmentState);
} else {
f.mInnerView = null;
}
}
// 最终回调到onActivityCreated
f.performActivityCreated(f.mSavedFragmentState);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
case Fragment.ACTIVITY_CREATED:
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
// 最终执行到Fragment onStart
f.performStart();
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
f.mResumed = true;
// 最终执行到Fragment onResume
f.performResume();
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}
} else if (f.mState > newState) {
... // 省略很多代码
}
f.mState = newState;
}
和add 的操作多重合,其中2,3会替换成相应的show 操作,然后关键看第7步的执行,show 会执行到FragmentManagerImpl 的showFragment 方法。从下面的代码中可以看出showFragment 是不会执行moveToState 方法的,而仅仅通过fragment.mView.setVisibility(View.VISIBLE);
将Fragment 中的mView 设置为可见(同理可得hideFragment 则是将mView 设置为不可见)。
public void showFragment(Fragment fragment, int transition, int transitionStyle) {
if (DEBUG) Log.v(TAG, "show: " + fragment);
if (fragment.mHidden) {
fragment.mHidden = false;
if (fragment.mView != null) {
Animation anim = loadAnimation(fragment, transition, true,
transitionStyle);
if (anim != null) {
setHWLayerAnimListenerIfAlpha(fragment.mView, anim);
fragment.mView.startAnimation(anim);
}
// 设置为可见
fragment.mView.setVisibility(View.VISIBLE);
}
if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
mNeedMenuInvalidate = true;
}
fragment.onHiddenChanged(false);
}
}
replace 的操作相当于执行了addFragment + removeFragment
操作,结果对应的是一个Fragment 生命周期的结束以及另一个Fragment 生命周期的开始。而show/hide 则只是对Fragment 中的View 进行了VISIBLE/GONE
操作。所有总结一下区别。
1.相对而言show/hide 方法会比较快。
2.replace 占用的内存可能比较少。show/hide 其实会将多个Fragment 一直保存着,而replace 时当内存不足会销毁被replace 的Fragment。
Fragment 中有一些坑,平常使用时好好的,放线上就会出现大量的crash,这也是因为对Fragment 的了解不够(不过真心还是有一些坑)。
这个异常发生在FragmentManagerImpl.enqueueAction
中,从下面的代码中可以得出来是因为Activity 执行了onDestory,一般出现情况是在请求完一个接口才去执行commit 操作,而此时home 回去Activity 执行了onDestroy 操作。但是Activity.isDestroyed()
需要在api 17以上调用,所有对于耗时操作以后才展示的Fragment 可以通过在Activity.onDestroy
中添加标示字段标示destroy 了或者直接try catch 掉。
if (mDestroyed || mHost == null) {
throw new IllegalStateException("Activity has been destroyed");
}
这个异常发生在FragmentManagerImpl.checkStateLoss
中,mStateSaved
置为true是在Activity.onSaveInstanceState
或者FragmentManagerImpl.dispatchStop
(执行到dispatchStop意味着会执行Activity.onStop
,这个之前一定执行了Activity.onSaveInstanceState
)之后。所以意思是当Activity 保存自身状态以后是不能在处理Fragment 的操作了。终其原因是Fragment 也包含了一些状态信息,Activity 保存状态信息的时候Fragment 也会执行保存状态信息的操作,如果保存了以后继续处理Fragment 状态信息变化的操作,新的状态信息就无法保留,所以抛出异常。一般出现情况是在请求完一个接口才去执行commit 操作,解决办法可以替换commit 操作为commitAllowingStateLoss
操作就行,commitAllowingStateLoss
不会去执行checkStateLoss
if (mStateSaved) {
throw new IllegalStateException(
"Can not perform this action after onSaveInstanceState");
}
有一个特殊的情况,如下栈信息。原因和上面的分析其实是一样的,也就是onBackPressed
在Activity.onSaveInstanceState
之后才执行的,而onBackPressed
一般是在用户退出按钮的时候才会执行。也就是这个异常出现的情况是在一个Activity
可见的情况下触发了Activity.onSaveInstanceState
然后点击了Back 按钮。因为所有的Activity
都是继承了一个封装的BaseActivity
,所以最后通过try catch解决的。
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.FragmentManagerImpl.checkStateLoss(FragmentManagerImpl.java:1413)
at android.app.FragmentManagerImpl.popBackStackImmediate(FragmentManagerImpl.java:576)
at android.app.Activity.onBackPressed(Activity.java:2520)
这个异常发生在FragmentManagerImpl.getFragment
中,一般发生在ViewPager.setDapter
,栈信息如下。
java.lang.IllegalStateException: Fragment no longer exists for key f2: index 2
at android.support.v4.app.FragmentManagerImpl.getFragment(FragmentManagerImpl.java)
at android.support.v4.app.FragmentStatePagerAdapter.restoreState(FragmentStatePagerAdapter.java)
at android.support.v4.view.ViewPager.setAdapter(ViewPager.java)
分析可得restoreState
只有在ViewPager.onRestoreInstanceState
之后才执行。同时也可以分析出第一次执行setAdapter
不会执行到restoreState
。java lang illegalstateexception fragement no longer exists for key f1 index 3 这里给了一个解决方法。但是这样会导致ViewPager
从onRestoreInstanceState
恢复过来的时候将无法恢复了,即home 回去以后Activity.onDestroy
执行,再次打开Activtiy 无法恢复。所以目前的解决办法是try catch 了。
@Override
public Parcelable saveState() {
return null;
}
Fragment 解决了碎片化问题?可以假设Activity 分成了上下两部分,使用两个View 分别展示在上面和下面,然后对两个View 进行各种不一样的操作也可以。那么为什么还需要使用Fragment。在View 中进行一些复杂的逻辑,比如网络请求等等会导致耦合度非常的高,同时对于Activity 的生命周期一些特殊逻辑也不是很好处理。Fragment 最终也是展示了一个View,但是封装出来,同时对应了Activity 的生命周期,代码的冗余也会减少很多。
打开一个新的Activity 的时候,需要做的操作可能包含了Window 的创建等等,相对来说需要的资源会更多,而使用Fragment 则不需要,这样在速度方面可能也比较的快。
关于Fragment 的坑也有一些,上面常见的异常信息里面列举了非常常见的几个,当需要延后打开一个Fragment 的时候,比如请求完接口在展示的时候,就需要考虑使用commitAllowingStateLoss
以及考虑Activity.onDestroy
已经执行了的情况。个人觉得更好的应该是在Activity 做较少的操作,直接在Activity.onCreate
的时候直接执行commit
,在Fragment 中去做相应的逻辑。
fragment transaction commit state loss
advocating against android fragments
Fragment全解析系列