Fragment源码简析(二)
上一篇 Fragment源码简析(一)
接上一篇
//BackStackRecord中executeOps方法最后调用到这里
mManager.moveToState(mManager.mCurState, true);
final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
int mCurState = Fragment.INITIALIZING;
//只看主流程代码
void moveToState(int newState, boolean always) {
mCurState = newState;
for (int i = 0; i < numAdded; i++) {
Fragment f = mAdded.get(i);
moveFragmentToExpectedState(f);
}
...........
}
}
moveFragmentToExpectedState又调到了moveToState的另一个重载方法,很长。
这里先停下,回到上一篇里的问题,FragmentManager的mHost为什么就是FragmentController的mHost呢?反推看看。在FragmentManagerImpl类里看到mHost被赋值的方法:
final class FragmentManagerImpl extends FragmentManager{
public void attachController(FragmentHostCallback host,
FragmentContainer container, Fragment parent) {
mHost = host;
mContainer = container;
mParent = parent;
}
................
}
public class FragmentController {
public void attachHost(Fragment parent) {
mHost.mFragmentManager.attachController(mHost, mHost /*container*/, parent);
}
....................
}
public class FragmentActivity extends BaseFragmentActivityApi16{
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mFragments.attachHost(null /*parent*/);
super.onCreate(savedInstanceState);
..........................
mFragments.dispatchCreate();
}
............
}
这样了解到从前往后的流程其实是:
FragmentActivity(onCreate) ->FragmentController(attachHost)->FragmentManagerImpl(attachController)
源头来自于FragmentActivity的onCreate方法,在onCreate最后调用了FragmentController的dispatchCreate,在FragmentController里有很多dispatch方法。比如:
public void dispatchCreate() {
mStateSaved = false;
dispatchStateChange(Fragment.CREATED);
}
public void dispatchActivityCreated() {
mStateSaved = false;
dispatchStateChange(Fragment.ACTIVITY_CREATED);
}
CREATED,ACTIVITY_CREATED这些都是Fragment的状态,状态一共是下面几种:
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.
int mState = INITIALIZING;
上面这些dispatch方法去了dispatchStateChange方法:
private void dispatchStateChange(int nextState) {
try {
mExecutingActions = true;
moveToState(nextState, false);//比如CREATED,ACTIVITY_CREATED
} finally {
mExecutingActions = false;
}
execPendingActions();
}
也是走到了moveToState方法:
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
boolean keepActive) {
// Fragments that are not currently added will sit in the onCreate() state.
if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
newState = Fragment.CREATED;
}
if (f.mRemoving && newState > f.mState) {
if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {
// Allow the fragment to be created so that it can be saved later.
newState = Fragment.CREATED;
} else {
// While removing a fragment, we can't change it to a higher state.
newState = f.mState;
}
}
// Defer start if requested; don't allow it to move to STARTED or higher
// if it's not already started.
if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
newState = Fragment.STOPPED;
}
if (f.mState <= newState) {
// For fragments that are created from a layout, when restoring from
// state we don't want to allow them to be created until they are
// being reloaded from the layout.
if (f.mFromLayout && !f.mInLayout) {
return;
}
if (f.getAnimatingAway() != null || f.getAnimator() != null) {
// The fragment is currently being animated... but! Now we
// want to move our state back up. Give up on waiting for the
// animation, move to whatever the final state should be once
// the animation is done, and then we can proceed from there.
f.setAnimatingAway(null);
f.setAnimator(null);
moveToState(f, f.getStateAfterAnimating(), 0, 0, true);
}
switch (f.mState) {
case Fragment.INITIALIZING:
if (newState > 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();
// If we have a target fragment, push it along to at least CREATED
// so that this one can rely on it as an initialized dependency.
if (f.mTarget != null) {
if (mActive.get(f.mTarget.mIndex) != f.mTarget) {
throw new IllegalStateException("Fragment " + f
+ " declared target fragment " + f.mTarget
+ " that does not belong to this FragmentManager!");
}
if (f.mTarget.mState < Fragment.CREATED) {
moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
}
}
dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
f.mCalled = false;
f.onAttach(mHost.getContext());
if (!f.mCalled) {
throw new SuperNotCalledException("Fragment " + f
+ " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
mHost.onAttachFragment(f);
} else {
f.mParentFragment.onAttachFragment(f);
}
dispatchOnFragmentAttached(f, mHost.getContext(), false);
if (!f.mIsCreated) {
dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
f.performCreate(f.mSavedFragmentState);
dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
} else {
f.restoreChildFragmentState(f.mSavedFragmentState);
f.mState = Fragment.CREATED;
}
f.mRetaining = false;
}
// fall through
case Fragment.CREATED:
// This is outside the if statement below on purpose; we want this to run
// even if we do a moveToState from CREATED => *, CREATED => CREATED, and
// * => CREATED as part of the case fallthrough above.
ensureInflatedFragmentView(f);
if (newState > Fragment.CREATED) {
if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
if (f.mContainerId == View.NO_ID) {
throwException(new IllegalArgumentException(
"Cannot create fragment "
+ f
+ " for a container view with no id"));
}
container = (ViewGroup) mContainer.onFindViewById(f.mContainerId);
if (container == null && !f.mRestored) {
String resName;
try {
resName = f.getResources().getResourceName(f.mContainerId);
} catch (NotFoundException e) {
resName = "unknown";
}
throwException(new IllegalArgumentException(
"No view found for id 0x"
+ Integer.toHexString(f.mContainerId) + " ("
+ resName
+ ") for fragment " + f));
}
}
f.mContainer = container;
f.mView = f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
f.mInnerView = f.mView;
f.mView.setSaveFromParentEnabled(false);
if (container != null) {
container.addView(f.mView);
}
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
f.onViewCreated(f.mView, f.mSavedFragmentState);
dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
false);
// Only animate the view if it is visible. This is done after
// dispatchOnFragmentViewCreated in case visibility is changed
f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
&& f.mContainer != null;
} else {
f.mInnerView = null;
}
}
f.performActivityCreated(f.mSavedFragmentState);
dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
if (f.mView != null) {
f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
// fall through
case Fragment.ACTIVITY_CREATED:
if (newState > Fragment.ACTIVITY_CREATED) {
f.mState = Fragment.STOPPED;
}
// fall through
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
f.performStart();
dispatchOnFragmentStarted(f, false);
}
// fall through
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
f.performResume();
dispatchOnFragmentResumed(f, false);
f.mSavedFragmentState = null;
f.mSavedViewState = null;
}
}
} else if (f.mState > newState) {
switch (f.mState) {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
f.performPause();
dispatchOnFragmentPaused(f, false);
}
// fall through
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
f.performStop();
dispatchOnFragmentStopped(f, false);
}
// fall through
case Fragment.STOPPED:
if (newState < Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "movefrom STOPPED: " + f);
f.performReallyStop();
}
// fall through
case Fragment.ACTIVITY_CREATED:
if (newState < Fragment.ACTIVITY_CREATED) {
if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
if (f.mView != null) {
// Need to save the current view state if not
// done already.
if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
saveFragmentViewState(f);
}
}
f.performDestroyView();
dispatchOnFragmentViewDestroyed(f, false);
if (f.mView != null && f.mContainer != null) {
// Stop any current animations:
f.mView.clearAnimation();
f.mContainer.endViewTransition(f.mView);
AnimationOrAnimator anim = null;
if (mCurState > Fragment.INITIALIZING && !mDestroyed
&& f.mView.getVisibility() == View.VISIBLE
&& f.mPostponedAlpha >= 0) {
anim = loadAnimation(f, transit, false,
transitionStyle);
}
f.mPostponedAlpha = 0;
if (anim != null) {
animateRemoveFragment(f, anim, newState);
}
f.mContainer.removeView(f.mView);
}
f.mContainer = null;
f.mView = null;
f.mInnerView = null;
f.mInLayout = false;
}
// fall through
case Fragment.CREATED:
if (newState < Fragment.CREATED) {
if (mDestroyed) {
// The fragment's containing activity is
// being destroyed, but this fragment is
// currently animating away. Stop the
// animation right now -- it is not needed,
// and we can't wait any more on destroying
// the fragment.
if (f.getAnimatingAway() != null) {
View v = f.getAnimatingAway();
f.setAnimatingAway(null);
v.clearAnimation();
} else if (f.getAnimator() != null) {
Animator animator = f.getAnimator();
f.setAnimator(null);
animator.cancel();
}
}
if (f.getAnimatingAway() != null || f.getAnimator() != null) {
// We are waiting for the fragment's view to finish
// animating away. Just make a note of the state
// the fragment now should move to once the animation
// is done.
f.setStateAfterAnimating(newState);
newState = Fragment.CREATED;
} else {
if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
if (!f.mRetaining) {
f.performDestroy();
dispatchOnFragmentDestroyed(f, false);
} else {
f.mState = Fragment.INITIALIZING;
}
f.performDetach();
dispatchOnFragmentDetached(f, false);
if (!keepActive) {
if (!f.mRetaining) {
makeInactive(f);
} else {
f.mHost = null;
f.mParentFragment = null;
f.mFragmentManager = null;
}
}
}
}
}
}
if (f.mState != newState) {
Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
+ "expected state " + newState + " found " + f.mState);
f.mState = newState;
}
}
moveToState很长,可以结合Fragment的生命周期函数看,这里看下Fragment的onCreateView回调后返回的View 怎么加入到之前布局的,在上面case Fragment.CREATED下:
f.mContainer = container;
f.mView = f.performCreateView(f.performGetLayoutInflater(
f.mSavedFragmentState), container, f.mSavedFragmentState);
if (f.mView != null) {
if (container != null) {
container.addView(f.mView);
}
if (f.mHidden) {
f.mView.setVisibility(View.GONE);
}
}
原来这么简单,只是调用普通的addView而已,隐藏Fragment也不过是调用普通的setVisibility。把Fragment当做有生命周期管理的复杂View,是不是理解简单点。
这里简单总结Fragment生命周期是怎么改变的:
Fragment和FragmentManagerImpl最初的状态是INITIALIZING;当FragmentActivity生命周期改变时,会调用到上面说的dispatch方法改变FragmentManagerImpl当前的状态值mCurState,然后FragmentManagerImpl会遍历Fragment(这里有两个列表mAdded和mActive),通过moveFragmentToExpectedState来调用moveToState改变Fragment当前的状态。