android源代码解读,Android fragment源码完全解析

缘起

一直以来,笔者对fragment相关的这一堆API,内部具体干了哪些事情不是很清楚,所以经常会用起来心里有点小疙瘩,不是那么踏实。总想着花些时间去源码中看看,大概从2、3年前也偶尔会点进去看看,那时看的有点云里雾里的,不是特别明白,最近又点进去看了看,加上可以单步代码,算是对其理解有所小成,于是乎趁着记忆还是新鲜的,特此记录下。

涉及到的类

和fragment相关的类有以下几个:

什么是Fragment

Fragment是Android3.0引入的API,号称是为了解决屏幕碎片化和帮助重用代码的构造。中文翻译为碎片、片段,或者理解成子Act,相比Activity更轻量级、更灵活,使用姿势一般有以下2种:

静态写在xml中,就和我们使用一般的widget一样,如下:

47d20351b1ac

写在act的xml布局文件中

在代码里动态生成,添加、删除等等,代码如下:

47d20351b1ac

通过代码添加

什么是FragmentTransaction

它封装了一系列对fragment的操作,并一次性执行这些操作。看眼它的API就能明白,全是各种add/remove/replace/show/hide等等操作。

什么是FragmentManager

它是和某个act相关联的,并不是全局唯一的,而是每个act都有一个自己的FragmentManager,内部有自己的状态mCurState,对应外部act的生命周期状态。它提供和act中fragment交互的API。

示例代码

private void addTestFragment() {

FragmentManager fm = getFragmentManager();

Fragment fragment = TestFragment.newInstance();

FragmentTransaction ft = fm.beginTransaction();

// ft.add(R.id.pf_base_fragment_container, fragment, "test_fragment");

ft.replace(R.id.pf_base_fragment_container, fragment);

ft.addToBackStack(null);

ft.commit();

}

之后的源码解析都按照这段示例代码来讲,源码基于Android6.0。

在开始分析之前,还得交代几个事情,如果我们仔细看了官方API会发现这里的FragmentManager、FragmentTransaction都是abstract的,其真正的实现API对外当然是没有暴露,不过我们看代码知道分别是,如下图:

47d20351b1ac

FragmentManager.java

47d20351b1ac

BackStackRecord.java

具体分析

通过FragmentTransaction这样的API,我们可以一次执行多个操作,就像这样:

ft.remove(R.id.fragment_container, fragment1);

ft.add(R.id.fragment_container, fragment2);

ft.hide(fragment3);

...等等还可以写很长

它是怎么做到的呢?关键是其内部的双向链表结构:

47d20351b1ac

Op的定义

接下来我们看下在此结构上,FragmentTransaction的一堆操作方法的实现,代码如下:

void addOp(Op op) {

// 典型的双向链表插入操作

if (mHead == null) {

mHead = mTail = op;

} else {

op.prev = mTail;

mTail.next = op;

mTail = op;

}

// 记录这些动画信息

op.enterAnim = mEnterAnim;

op.exitAnim = mExitAnim;

op.popEnterAnim = mPopEnterAnim;

op.popExitAnim = mPopExitAnim;

mNumOp++;

}

public FragmentTransaction add(Fragment fragment, String tag) {

doAddOp(0, fragment, tag, OP_ADD);

return this;

}

public FragmentTransaction add(int containerViewId, Fragment fragment) {

doAddOp(containerViewId, fragment, null, OP_ADD);

return this;

}

public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {

doAddOp(containerViewId, fragment, tag, OP_ADD);

return this;

}

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对象上

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对象上

fragment.mContainerId = fragment.mFragmentId = containerViewId;

}

Op op = new Op();

op.cmd = opcmd;

op.fragment = fragment;

addOp(op);

}

public FragmentTransaction replace(int containerViewId, Fragment fragment) {

return replace(containerViewId, fragment, null);

}

public FragmentTransaction replace(int containerViewId, Fragment fragment, String tag) {

if (containerViewId == 0) {

throw new IllegalArgumentException("Must use non-zero containerViewId");

}

doAddOp(containerViewId, fragment, tag, OP_REPLACE);

return this;

}

public FragmentTransaction remove(Fragment fragment) {

Op op = new Op();

op.cmd = OP_REMOVE;

op.fragment = fragment;

addOp(op);

return this;

}

public FragmentTransaction hide(Fragment fragment) {

Op op = new Op();

op.cmd = OP_HIDE;

op.fragment = fragment;

addOp(op);

return this;

}

public FragmentTransaction show(Fragment fragment) {

Op op = new Op();

op.cmd = OP_SHOW;

op.fragment = fragment;

addOp(op);

return this;

}

public FragmentTransaction detach(Fragment fragment) {

Op op = new Op();

op.cmd = OP_DETACH;

op.fragment = fragment;

addOp(op);

return this;

}

public FragmentTransaction attach(Fragment fragment) {

Op op = new Op();

op.cmd = OP_ATTACH;

op.fragment = fragment;

addOp(op);

return this;

}

public FragmentTransaction setCustomAnimations(int enter, int exit) {

return setCustomAnimations(enter, exit, 0, 0);

}

public FragmentTransaction setCustomAnimations(int enter, int exit,

int popEnter, int popExit) {

mEnterAnim = enter;

mExitAnim = exit;

mPopEnterAnim = popEnter;

mPopExitAnim = popExit;

return this;

}

public FragmentTransaction setTransition(int transition) {

mTransition = transition;

return this;

}

@Override

public FragmentTransaction addSharedElement(View sharedElement, String name) {

String transitionName = sharedElement.getTransitionName();

if (transitionName == null) {

throw new IllegalArgumentException("Unique transitionNames are required for all" +

" sharedElements");

}

if (mSharedElementSourceNames == null) {

mSharedElementSourceNames = new ArrayList();

mSharedElementTargetNames = new ArrayList();

}

mSharedElementSourceNames.add(transitionName);

mSharedElementTargetNames.add(name);

return this;

}

public FragmentTransaction setTransitionStyle(int styleRes) {

mTransitionStyle = styleRes;

return this;

}

public FragmentTransaction addToBackStack(String name) {

if (!mAllowAddToBackStack) {

throw new IllegalStateException(

"This FragmentTransaction is not allowed to be added to the back stack.");

}

mAddToBackStack = true;

mName = name;

return this;

}

从源码我们可以看出,各种不同操作方法内部实际上只是个不同cmd的Op对象,通过双向链表链起来了而已,至于为什么要是双向的呢,单链表不行吗?那是因为Fragment在act层面维护了一个回退栈,即如果你调用了ft.addToBackStack(null);这样的代码,那么当你按下back键的时候不是直接结束当前act,而是先从fragment栈里尝试pop出来栈顶的fragment。它不仅要向前进,还得支持向后退。

紧接着的是commit的源码,如下:

public int commit() {

return commitInternal(false);

}

public int commitAllowingStateLoss() {

return commitInternal(true);

}

int commitInternal(boolean allowStateLoss) {

if (mCommitted) {

throw new IllegalStateException("commit already called");

}

if (FragmentManagerImpl.DEBUG) {

Log.v(TAG, "Commit: " + this);

LogWriter logw = new LogWriter(Log.VERBOSE, TAG);

PrintWriter pw = new FastPrintWriter(logw, false, 1024);

dump(" ", null, pw, null);

pw.flush();

}

mCommitted = true;

if (mAddToBackStack) {

mIndex = mManager.allocBackStackIndex(this);

} else {

mIndex = -1;

}

mManager.enqueueAction(this, allowStateLoss);

return mIndex;

}

// FragmentManagerImpl#enqueueAction方法

/**

* Adds an action to the queue of pending actions.

*

* @param action the action to add

* @param allowStateLoss whether to allow loss of state information

* @throws IllegalStateException if the activity has been destroyed

*/

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();

}

mPendingActions.add(action);

if (mPendingActions.size() == 1) {

mHost.getHandler().removeCallbacks(mExecCommit);

mHost.getHandler().post(mExecCommit);

}

}

}

我们看到commit方法并没有立即执行这个动作,只是入队了action(通过mPendingActions.add(action);),系统会在下次event loop到来时执行它。

FragmentManagerImpl的其他关键方法

Runnable mExecCommit = new Runnable() {

@Override

public void run() {

execPendingActions();

}

};

/**

* Only call from main thread!

*/

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.toArray(mTmpActions);

mPendingActions.clear();

mHost.getHandler().removeCallbacks(mExecCommit);

}

mExecutingActions = true;

for (int i=0; i

mTmpActions[i].run();

mTmpActions[i] = null;

}

mExecutingActions = false;

didSomething = true;

}

if (mHavePendingDeferredStart) {

boolean loadersRunning = false;

for (int i=0; i

Fragment f = mActive.get(i);

if (f != null && f.mLoaderManager != null) {

loadersRunning |= f.mLoaderManager.hasRunningLoaders();

}

}

if (!loadersRunning) {

mHavePendingDeferredStart = false;

startPendingDeferredFragments();

}

}

return didSomething;

}

具体要执行的action就是BackStackRecord#run方法,因为我们注意到它自己实现了Runnable接口,来看下其实现:

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);

SparseArray firstOutFragments = new SparseArray();

SparseArray lastInFragments = new SparseArray();

calculateFragments(firstOutFragments, lastInFragments);

beginTransition(firstOutFragments, lastInFragments, false);

Op op = mHead;

while (op != null) {

switch (op.cmd) {

case OP_ADD: {

Fragment f = op.fragment;

f.mNextAnim = op.enterAnim;

mManager.addFragment(f, false);

}

break;

case OP_REPLACE: {

Fragment f = op.fragment;

int containerId = f.mContainerId;

if (mManager.mAdded != null) {

for (int i = 0; i < mManager.mAdded.size(); i++) {

Fragment old = mManager.mAdded.get(i);

if (FragmentManagerImpl.DEBUG) {

Log.v(TAG,

"OP_REPLACE: adding=" + f + " old=" + old);

}

// 注意这个判断,必须是同一个containerId里面的,换句话说你如果是在2个不同的container里面做fragment的replace操作,互相是不会影响的

if (old.mContainerId == containerId) {

if (old == f) {

op.fragment = f = null;

} else {

if (op.removed == null) {

op.removed = new ArrayList();

}

op.removed.add(old);

old.mNextAnim = op.exitAnim;

if (mAddToBackStack) {

old.mBackStackNesting += 1;

if (FragmentManagerImpl.DEBUG) {

Log.v(TAG, "Bump nesting of "

+ old + " to " + old.mBackStackNesting);

}

}

mManager.removeFragment(old, mTransition, mTransitionStyle);

}

}

}

}

// 注意这个非空判断,因为replace自己的时候f会被置为null,相当于什么也不会做的

if (f != null) {

f.mNextAnim = op.enterAnim;

mManager.addFragment(f, false);

}

}

break;

case OP_REMOVE: {

Fragment f = op.fragment;

f.mNextAnim = op.exitAnim;

mManager.removeFragment(f, mTransition, mTransitionStyle);

}

break;

case OP_HIDE: {

Fragment f = op.fragment;

f.mNextAnim = op.exitAnim;

mManager.hideFragment(f, mTransition, mTransitionStyle);

}

break;

case OP_SHOW: {

Fragment f = op.fragment;

f.mNextAnim = op.enterAnim;

mManager.showFragment(f, mTransition, mTransitionStyle);

}

break;

case OP_DETACH: {

Fragment f = op.fragment;

f.mNextAnim = op.exitAnim;

mManager.detachFragment(f, mTransition, mTransitionStyle);

}

break;

case OP_ATTACH: {

Fragment f = op.fragment;

f.mNextAnim = op.enterAnim;

mManager.attachFragment(f, mTransition, mTransitionStyle);

}

break;

default: {

throw new IllegalArgumentException("Unknown cmd: " + op.cmd);

}

}

op = op.next;

}

// 不带fragment参数的状态转移

mManager.moveToState(mManager.mCurState, mTransition,

mTransitionStyle, true);

if (mAddToBackStack) {

mManager.addBackStackState(this);

}

}

这个方法主要做的事情是向前遍历Op双向链表,根据cmd的不同调用FragmentManagerImpl的以下方法,特别注意下这里的OP_REPLACE cmd,看代码我们知道它其实相当于add/remove的组合,即如果有added会把所以已经added了的先remove掉,再将新的add进去,效果上是这样。

public void addFragment(Fragment fragment, boolean moveToStateNow) {

if (mAdded == null) {

mAdded = new ArrayList();

}

if (DEBUG) Log.v(TAG, "add: " + fragment);

makeActive(fragment);

if (!fragment.mDetached) {

if (mAdded.contains(fragment)) {

throw new IllegalStateException("Fragment already added: " + fragment);

}

mAdded.add(fragment);

fragment.mAdded = true;

fragment.mRemoving = false;

if (fragment.mHasMenu && fragment.mMenuVisible) {

mNeedMenuInvalidate = true;

}

if (moveToStateNow) {

moveToState(fragment);

}

}

}

public void removeFragment(Fragment fragment, int transition, int transitionStyle) {

if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);

// 加到回退栈中和不加的区别

final boolean inactive = !fragment.isInBackStack();

if (!fragment.mDetached || inactive) {

if (false) {

// Would be nice to catch a bad remove here, but we need

// time to test this to make sure we aren't crashes cases

// where it is not a problem.

if (!mAdded.contains(fragment)) {

throw new IllegalStateException("Fragment not added: " + fragment);

}

}

if (mAdded != null) {

mAdded.remove(fragment);

}

if (fragment.mHasMenu && fragment.mMenuVisible) {

mNeedMenuInvalidate = true;

}

fragment.mAdded = false;

fragment.mRemoving = true;

// 没有加到回退栈中则状态退的更彻底,到状态0而不是状态1,区别就是最后的几个destory相关的callback会不会被调用。

moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,

transition, transitionStyle, false);

}

}

public void hideFragment(Fragment fragment, int transition, int transitionStyle) {

if (DEBUG) Log.v(TAG, "hide: " + fragment);

if (!fragment.mHidden) {

fragment.mHidden = true;

if (fragment.mView != null) {

Animator anim = loadAnimator(fragment, transition, false,

transitionStyle);

if (anim != null) {

anim.setTarget(fragment.mView);

// Delay the actual hide operation until the animation finishes, otherwise

// the fragment will just immediately disappear

final Fragment finalFragment = fragment;

anim.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

if (finalFragment.mView != null) {

finalFragment.mView.setVisibility(View.GONE);

}

}

});

setHWLayerAnimListenerIfAlpha(finalFragment.mView, anim);

anim.start();

} else {

fragment.mView.setVisibility(View.GONE);

}

}

if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {

mNeedMenuInvalidate = true;

}

fragment.onHiddenChanged(true);

}

}

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) {

Animator anim = loadAnimator(fragment, transition, true,

transitionStyle);

if (anim != null) {

anim.setTarget(fragment.mView);

setHWLayerAnimListenerIfAlpha(fragment.mView, anim);

anim.start();

}

fragment.mView.setVisibility(View.VISIBLE);

}

if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {

mNeedMenuInvalidate = true;

}

fragment.onHiddenChanged(false);

}

}

public void detachFragment(Fragment fragment, int transition, int transitionStyle) {

if (DEBUG) Log.v(TAG, "detach: " + fragment);

if (!fragment.mDetached) {

fragment.mDetached = true;

if (fragment.mAdded) {

// We are not already in back stack, so need to remove the fragment.

if (mAdded != null) {

if (DEBUG) Log.v(TAG, "remove from detach: " + fragment);

mAdded.remove(fragment);

}

if (fragment.mHasMenu && fragment.mMenuVisible) {

mNeedMenuInvalidate = true;

}

fragment.mAdded = false;

moveToState(fragment, Fragment.CREATED, transition, transitionStyle, false);

}

}

}

public void attachFragment(Fragment fragment, int transition, int transitionStyle) {

if (DEBUG) Log.v(TAG, "attach: " + fragment);

if (fragment.mDetached) {

fragment.mDetached = false;

if (!fragment.mAdded) {

if (mAdded == null) {

mAdded = new ArrayList();

}

if (mAdded.contains(fragment)) {

throw new IllegalStateException("Fragment already added: " + fragment);

}

if (DEBUG) Log.v(TAG, "add from attach: " + fragment);

mAdded.add(fragment);

fragment.mAdded = true;

if (fragment.mHasMenu && fragment.mMenuVisible) {

mNeedMenuInvalidate = true;

}

moveToState(fragment, mCurState, transition, transitionStyle, false);

}

}

}

上面的run方法在对这一系列Op处理完后,调用了下面的方法:

mManager.moveToState(mManager.mCurState, mTransition, mTransitionStyle, true);,对应的源码如下:

void moveToState(Fragment f) {

moveToState(f, mCurState, 0, 0, false);

}

void moveToState(int newState, boolean always) {

moveToState(newState, 0, 0, always);

}

// 这里调用的是这个方法

void moveToState(int newState, int transit, int transitStyle, boolean always) {

if (mHost == null && newState != Fragment.INITIALIZING) {

throw new IllegalStateException("No activity");

}

if (!always && mCurState == newState) {

return;

}

mCurState = newState;

if (mActive != null) {

boolean loadersRunning = false;

for (int i=0; i

Fragment f = mActive.get(i);

if (f != null) {

// fragment状态改变的方法,其各种生命周期回调也在这里调用,是最重要的一个方法!!!

moveToState(f, newState, transit, transitStyle, false);

if (f.mLoaderManager != null) {

loadersRunning |= f.mLoaderManager.hasRunningLoaders();

}

}

}

if (!loadersRunning) {

startPendingDeferredFragments();

}

if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {

mHost.onInvalidateOptionsMenu();

mNeedMenuInvalidate = false;

}

}

}

这里我们需要对mManager.mCurState这个值的变化细说下,其初始值是这样的:

int mCurState = Fragment.INITIALIZING;

Fragment的所有可能状态:

static final int INVALID_STATE = -1; // Invalid state used as a null value.

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.

FragmentManager中有一堆public void dispatchxxx这样的方法,如下:

public void dispatchCreate() {

mStateSaved = false;

moveToState(Fragment.CREATED, false);

}

public void dispatchActivityCreated() {

mStateSaved = false;

moveToState(Fragment.ACTIVITY_CREATED, false);

}

public void dispatchStart() {

mStateSaved = false;

moveToState(Fragment.STARTED, false);

}

public void dispatchResume() {

mStateSaved = false;

moveToState(Fragment.RESUMED, false);

}

public void dispatchPause() {

moveToState(Fragment.STARTED, false);

}

public void dispatchStop() {

moveToState(Fragment.STOPPED, false);

}

public void dispatchDestroyView() {

moveToState(Fragment.CREATED, false);

}

public void dispatchDestroy() {

mDestroyed = true;

execPendingActions();

moveToState(Fragment.INITIALIZING, false);

mHost = null;

mContainer = null;

mParent = null;

}

而这些正好是和act的生命周期对应起来,也就是说这些方法是随着act进入到不同的生命周期而被调用的,即mCurState的值是被这些方法触发设置的。比如act进入到了Resume状态,那么FragmentManagerImpl.mCurState也就等于Fragment.RESUMED。

最后,我们分析下fragment状态转移最重要的一个方法,如下:

void moveToState(Fragment f, int newState, int transit, int transitionStyle,

boolean keepActive) {

if (DEBUG && false) Log.v(TAG, "moveToState: " + f

+ " oldState=" + f.mState + " newState=" + newState

+ " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));

// 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) {

// 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.mAnimatingAway != 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.mAnimatingAway = null;

moveToState(f, f.mStateAfterAnimating, 0, 0, true);

}

switch (f.mState) {

case Fragment.INITIALIZING:

if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);

if (f.mSavedFragmentState != null) {

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;

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);

}

if (!f.mRetaining) {

f.performCreate(f.mSavedFragmentState);

}

f.mRetaining = false;

if (f.mFromLayout) {

// For fragments that are part of the content view

// layout, we need to instantiate the view immediately

// and the inflater will take care of adding it.

f.mView = f.performCreateView(f.getLayoutInflater(

f.mSavedFragmentState), null, f.mSavedFragmentState);

if (f.mView != null) {

f.mView.setSaveFromParentEnabled(false);

if (f.mHidden) f.mView.setVisibility(View.GONE);

f.onViewCreated(f.mView, f.mSavedFragmentState);

}

}

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) {

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;

f.mView = f.performCreateView(f.getLayoutInflater(

f.mSavedFragmentState), container, f.mSavedFragmentState);

if (f.mView != null) {

f.mView.setSaveFromParentEnabled(false);

if (container != null) {

Animator anim = loadAnimator(f, transit, true,

transitionStyle);

if (anim != null) {

anim.setTarget(f.mView);

setHWLayerAnimListenerIfAlpha(f.mView, anim);

anim.start();

}

container.addView(f.mView);

}

if (f.mHidden) f.mView.setVisibility(View.GONE);

f.onViewCreated(f.mView, f.mSavedFragmentState);

}

}

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);

f.performStart();

}

case Fragment.STARTED:

if (newState > Fragment.STARTED) {

if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);

f.mResumed = true;

f.performResume();

// Get rid of this in case we saved it and never needed it.

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();

f.mResumed = false;

}

case Fragment.STARTED:

if (newState < Fragment.STARTED) {

if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);

f.performStop();

}

case Fragment.STOPPED:

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();

if (f.mView != null && f.mContainer != null) {

Animator anim = null;

if (mCurState > Fragment.INITIALIZING && !mDestroyed) {

anim = loadAnimator(f, transit, false,

transitionStyle);

}

if (anim != null) {

final ViewGroup container = f.mContainer;

final View view = f.mView;

final Fragment fragment = f;

container.startViewTransition(view);

f.mAnimatingAway = anim;

f.mStateAfterAnimating = newState;

anim.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator anim) {

container.endViewTransition(view);

if (fragment.mAnimatingAway != null) {

fragment.mAnimatingAway = null;

moveToState(fragment, fragment.mStateAfterAnimating,

0, 0, false);

}

}

});

anim.setTarget(f.mView);

setHWLayerAnimListenerIfAlpha(f.mView, anim);

anim.start();

}

f.mContainer.removeView(f.mView);

}

f.mContainer = null;

f.mView = null;

}

case Fragment.CREATED:

if (newState < Fragment.CREATED) {

if (mDestroyed) {

if (f.mAnimatingAway != null) {

// 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.

Animator anim = f.mAnimatingAway;

f.mAnimatingAway = null;

anim.cancel();

}

}

if (f.mAnimatingAway != 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.mStateAfterAnimating = newState;

newState = Fragment.CREATED;

} else {

if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);

if (!f.mRetaining) {

f.performDestroy();

}

f.mCalled = false;

f.onDetach();

if (!f.mCalled) {

throw new SuperNotCalledException("Fragment " + f

+ " did not call through to super.onDetach()");

}

if (!keepActive) {

if (!f.mRetaining) {

makeInactive(f);

} else {

f.mHost = null;

f.mParentFragment = null;

f.mFragmentManager = null;

f.mChildFragmentManager = null;

}

}

}

}

}

}

f.mState = newState;

}

这个方法最终会将FragmentManager的状态赋值给fragment,另外这个方法会根据不同的state调用各种onAttach, Fragment.performXXX,进而调到用户自己override的fragment的各种生命周期方法,比如onCreate、onCreateView等等。

总结

show/hideFragment只是改变fragment根View的visibility,最多带上个动画效果,另外只有本身是hidden的fragment,调用show才起作用,否则没用的,fragment.onHiddenChanged会被触发;其次不会有生命周期callback触发,当然了这些操作的前提是已经被add了的fragment;

addFragment的时候,不管加不加入回退栈都一样,经历的生命周期如下:onAttach、onCreate、onCreateView、onActivityCreate、onStart、onResume;

removeFragment的时候,经历的生命周期如下:onPause、onStop、onDestroyView,如果不加回退栈还会继续走

onDestroy、onDetach;remove的时候不仅从mAdded中移除fragment,也从mActive中移除了;

47d20351b1ac

FragmentManagerImpl中关键字段申明

attach/detachFragment的前提都是已经add了的fragment,其生命周期回调不受回退栈影响。attach的时候onCreateView、onActivityCreate、onStart、onResume会被调用;detach的时候onPause、onStop、onDestroyView会被调用,onDestroy、onDetach不会被调用;对应的fragment只是从mAdded中移除了;

remove、detachFragment的时候,当FragmentManagerImpl.makeInactive()被调用的话,fragment就变成了一个空壳,里面绝大部分字段都会被置空,注意只是系统内部自己管理的字段,假如你在自己的fragment子类中引入了新的字段,当你重用这些类的对象时要自己处理这种情况(即系统不会reset你自己造的字段),代码如下:

void makeInactive(Fragment f) {

if (f.mIndex < 0) {

return;

}

if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);

mActive.set(f.mIndex, null);

if (mAvailIndices == null) {

mAvailIndices = new ArrayList();

}

mAvailIndices.add(f.mIndex);

mHost.inactivateFragment(f.mWho);

f.initState();

}

// Fragment.initState方法

/**

* Called by the fragment manager once this fragment has been removed,

* so that we don't have any left-over state if the application decides

* to re-use the instance. This only clears state that the framework

* internally manages, not things the application sets.

*/

void initState() {

mIndex = -1;

mWho = null;

mAdded = false;

mRemoving = false;

mResumed = false;

mFromLayout = false;

mInLayout = false;

mRestored = false;

mBackStackNesting = 0;

mFragmentManager = null;

mChildFragmentManager = null;

mHost = null;

mFragmentId = 0;

mContainerId = 0;

mTag = null;

mHidden = false;

mDetached = false;

mRetaining = false;

mLoaderManager = null;

mLoadersStarted = false;

mCheckedForLoaderManager = false;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值