您的位置:首页 > 其它

Fragment加载过程分析

2014-11-17 10:04 260 查看
Fragment加载到屏幕上的代码非常简单。getFragmentManager().beginTransaction().add(int addId,Fragment addFragment,String tag).commit();但是具体过程我们来看一下:

首先看getFragmentMananger()方法:它定义在Activity中:

[java] view
plaincopy

public FragmentManager getFragmentManager() {

return mFragments;

}

它只是直接返回了成员变量mFragments。这个变量的类型是FragmentManagerImpl.它是FragmentManager的子类。与FragmentManager和FragmentManagerState处于同一个文件中。而FragmentManager实际上是一个抽象类。

接着看第二个。beginTransaction():

[java] view
plaincopy

public FragmentTransaction beginTransaction() {

return new BackStackRecord(this);

}

将此FragmentManager本身赋给了一个叫做BackStackRecord的类。并将此Manager的实例在内部用一个成员变量保存起来。用于做回退栈栈管理之类的操作。故名思义。这是用于做Fragment回退栈记录处理的类。接着往下看add方法。这个方法是定义在BackStackRecord类中。

[java] view
plaincopy

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

doAddOp(containerViewId, fragment, tag, OP_ADD);

return this;

}

这个方法里面直接将成员变量交给一个叫做doAddOp的方法进行处理。再多传了一个标志位。用于区分add、remove、replace等操作:

[java] view
plaincopy

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

}

这个方法中进行了一些保护性的判断。并将containerViewId和tag赋给要添加的fragment.并将此fragment放于一个Op的容器类中。类似我们常用的ViewHolder。它定义在BackStackRecord类中。而在add方法中传过来的参数OP_ADD。将它保存在了op类中的cmd变量中。

[java] view
plaincopy

static final class Op {

Op next;

Op prev;

int cmd;

Fragment fragment;

int enterAnim;

int exitAnim;

int popEnterAnim;

int popExitAnim;

ArrayList<Fragment> removed;

}

接着看addOp方法:

[java] view
plaincopy

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

}

这个方法就是把封装了此fragment的op实例保存起来。并将设置的动画也加入其中。

到此add方法算是介绍完了。接下来是commit方法,它也是在BackStackRecord类中定义。

[java] view
plaincopy

public int commit() {

return commitInternal(false);

}

此处直接调用类中的commitInternal方法。传一个false进入。而我们知道fragment提交时还有一个叫做commitAllowingStateLoss的方法。这个方法内部也是直接调用commitInternal方法。但是传入一个true进入:

[java] view
plaincopy

int commitInternal(boolean allowStateLoss) {

if (mCommitted) throw new IllegalStateException("commit already called");

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

mCommitted = true;

if (mAddToBackStack) {

mIndex = mManager.allocBackStackIndex(this);

} else {

mIndex = -1;

}

mManager.enqueueAction(this, allowStateLoss);

return mIndex;

}

这个方法中将对此fragment进行入栈操作。使用FragmentManagerImpl对象的enqueueAction方法将将回退栈记录管理类传回去。

下面回到FragmentManagerImpl类中:

[java] view
plaincopy

public void enqueueAction(Runnable action, boolean allowStateLoss) {

if (!allowStateLoss) {

checkStateLoss();

}

synchronized (this) {

if (mActivity == null) {

throw new IllegalStateException("Activity has been destroyed");

}

if (mPendingActions == null) {

mPendingActions = new ArrayList<Runnable>();

}

mPendingActions.add(action);

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

mActivity.mHandler.removeCallbacks(mExecCommit);

mActivity.mHandler.post(mExecCommit);

}

}

}

allowStateLoss就是当时commitInternal传入的变量。在commit时为false。在commitAllowingStateLoss时为true。所以。在为false时。会调用checkStateLoss来检查状态。接着用了一个同步锁。在里面将BackStackRecord实例装入了mPendingActions的数组中。BackStackRecord是Runnable的子类。再将mExecCommit加入到主线程的handler中进行处理。这也是我们可以连续使用add、replace等在同一条语句的原因。在mExecCommit的Runnable对象中。调用了execPendingActions方法。

[java] view
plaincopy

public boolean execPendingActions() {

if (mExecutingActions) {

throw new IllegalStateException("Recursive entry to executePendingTransactions");

}

if (Looper.myLooper() != mActivity.mHandler.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();

mActivity.mHandler.removeCallbacks(mExecCommit);

}

mExecutingActions = true;

for (int i=0; i<numActions; i++) {

mTmpActions[i].run();

mTmpActions[i] = null;

}

mExecutingActions = false;

didSomething = true;

}

if (mHavePendingDeferredStart) {

boolean loadersRunning = false;

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

Fragment f = mActive.get(i);

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

loadersRunning |= f.mLoaderManager.hasRunningLoaders();

}

}

if (!loadersRunning) {

mHavePendingDeferredStart = false;

startPendingDeferredFragments();

}

}

return didSomething;

}

这个方法中用了一个while(true)循环对mPendingActions进行操作。所以接着看mPendingActions里面的Runnable对象的run方法。而这个里面保存的是BackStackRecord对象。所以又回到BackStackRecord类中:

[java] view
plaincopy

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

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;

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

if (f == null || old.mContainerId == f.mContainerId) {

if (old == f) {

op.fragment = f = null;

} else {

if (op.removed == null) {

op.removed = new ArrayList<Fragment>();

}

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

}

}

}

}

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;

}

mManager.moveToState(mManager.mCurState, mTransition,

mTransitionStyle, true);

if (mAddToBackStack) {

mManager.addBackStackState(this);

}

}

可以看见。在run方法中。它也进行了一个while(true)循环。在里面从Op中一个个的通过next变量取出下一个Op实例。每个Op实例包装一个Fragment实例。方法内部用switch对不同的操作进行区别运行。此处我们看OP_ADD中的代码。它把Fragment实例和它的进行动画取出来。使用FragmentManager管理类addFragment。在addFragment方法中。此将Fragment加入了一个叫做mAdded的成员变量中。类型是ArrayList。范型是Fragment。代表已加入的fragment。然后跳出switch语句。执行FragmentManagerImpl中的moveToState方法。

[java] view
plaincopy

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

if (mActivity == 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<mActive.size(); i++) {

Fragment f = mActive.get(i);

if (f != null) {

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

if (f.mLoaderManager != null) {

loadersRunning |= f.mLoaderManager.hasRunningLoaders();

}

}

}

if (!loadersRunning) {

startPendingDeferredFragments();

}

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

mActivity.invalidateOptionsMenu();

mNeedMenuInvalidate = false;

}

}

}

一般我们commit的地方在Activity的super.onCreate之后。此处newState为ACTIVITY_CREATED 。状态值总共有如下几个:

[java] view
plaincopy

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.

在此方法中。程序调用五个参数的moveToState

[java] view
plaincopy

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

// 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.mActivity = mActivity;

f.mParentFragment = mParent;

f.mFragmentManager = mParent != null

? mParent.mChildFragmentManager : mActivity.mFragments;

f.mCalled = false;

f.onAttach(mActivity);

if (!f.mCalled) {

throw new SuperNotCalledException("Fragment " + f

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

}

if (f.mParentFragment == null) {

mActivity.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.mInnerView = f.mView;

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

container = (ViewGroup)mContainer.findViewById(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.mInnerView = f.mView;

f.mView = NoSaveStateFrameLayout.wrap(f.mView);

if (container != null) {

Animation anim = loadAnimation(f, transit, true,

transitionStyle);

if (anim != null) {

f.mView.startAnimation(anim);

}

container.addView(f.mView);

}

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

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

} else {

f.mInnerView = null;

}

}

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

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:

if (newState < Fragment.STOPPED) {

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

f.performReallyStop();

}

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 (!mActivity.isFinishing() && f.mSavedViewState == null) {

saveFragmentViewState(f);

}

}

f.performDestroyView();

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

Animation anim = null;

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

anim = loadAnimation(f, transit, false,

transitionStyle);

}

if (anim != null) {

final Fragment fragment = f;

f.mAnimatingAway = f.mView;

f.mStateAfterAnimating = newState;

anim.setAnimationListener(new AnimationListener() {

@Override

public void onAnimationEnd(Animation animation) {

if (fragment.mAnimatingAway != null) {

fragment.mAnimatingAway = null;

moveToState(fragment, fragment.mStateAfterAnimating,

0, 0, false);

}

}

@Override

public void onAnimationRepeat(Animation animation) {

}

@Override

public void onAnimationStart(Animation animation) {

}

});

f.mView.startAnimation(anim);

}

f.mContainer.removeView(f.mView);

}

f.mContainer = null;

f.mView = null;

f.mInnerView = 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.

View v = f.mAnimatingAway;

f.mAnimatingAway = null;

v.clearAnimation();

}

}

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.mActivity = null;

f.mFragmentManager = null;

}

}

}

}

}

}

f.mState = newState;

}

重要的终于到了啊!这个方法中会先依次走INITIALIZING,CREATED,ACTIVITY_CREATED代码段。之后会根据Activity的生命周期走自己相应的生命周期函数。在此对应的是STARTED,RESUMED;

由于是初次加载Fragment。所以f.mState是小于newState的。所以走的都是f.mState<newState中的switch语句。

首先看INITIALIZING状态:

[java] view
plaincopy

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.mActivity = mActivity;

f.mFragmentManager = mActivity.mFragments;

f.mCalled = false;

f.onAttach(mActivity);

if (!f.mCalled) {

throw new SuperNotCalledException("Fragment " + f

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

}

mActivity.onAttachFragment(f);

if (!f.mRetaining) {

f.mCalled = false;

f.onCreate(f.mSavedFragmentState);

if (!f.mCalled) {

throw new SuperNotCalledException("Fragment " + f

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

}

}

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.onCreateView(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:

在f.mSavedFragmentState != null这个条件判断语句块中。是屏幕切换时或因其他原因引起的fragment被销毁后重新恢复时走的语句块。在此不用理会。接着后面,熟悉的代码出现了,f.onAttach(mActivity),第一个生命周期方法。这里面就可以拿到与此fragment相绑定的Activity的实例。接着往下看。f.onCreate(f.mSavedFragmentState)。走onCreate回调了。

而f.mFromLayout在此时为false。故不用理会。

接着。来看CREATED状态:

[java] view
plaincopy

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)mActivity.findViewById(f.mContainerId);

if (container == null && !f.mRestored) {

throw new IllegalArgumentException("No view found for id 0x"

+ Integer.toHexString(f.mContainerId)

+ " for fragment " + f);

}

}

f.mContainer = container;

f.mView = f.onCreateView(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);

anim.start();

}

container.addView(f.mView);

}

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

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

}

}

f.mCalled = false;

f.onActivityCreated(f.mSavedFragmentState);

if (!f.mCalled) {

throw new SuperNotCalledException("Fragment " + f

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

}

if (f.mView != null) {

f.restoreViewState();

}

f.mSavedFragmentState = null;

}

case Fragment.ACTIVITY_CREATED:

重点来了!newState此时的值为ACTIVITY_CREATED。故可以进入语句块,在内部先通过Activity的findViewById方法通过add的containerid来得到要添加fragment的ViewGroup。再将其赋给fragment的mContainer成员变量中。接下来通过fragment的onCreateView回调。将创建的view放入fragment的view成员变量中。接下来就是加载fragment的动画以及将创建的view通过addView方法放于容器中了。至此。成功将fragment嵌入到了界面上
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: