[Android]Fragment源代码分析(二) 状态
我们上一讲,抛出来一个问题,就是当Activity的onCreateView的时候,是怎样构造Fragment中的View參数。要回答这个问题我们先要了解Fragment的状态,这是Fragment管理中很重要的一环。我们先来看一下FragmentActivity提供的一些核心回调:
@Override protected void onCreate(Bundle savedInstanceState) { mFragments.attachActivity(this, mContainer, null); // Old versions of the platform didn't do this! if (getLayoutInflater().getFactory() == null) { getLayoutInflater().setFactory(this); } super.onCreate(savedInstanceState); .... mFragments.dispatchCreate(); }我们跟入mFragments.dispatchCreate方法中:
public void dispatchCreate() { mStateSaved = false; moveToState(Fragment.CREATED, false); }
我们看到,对于FragmentManager来说,做了一次状态转换。我上一篇说过FragmentManager是及其重要的类,它承担了Fragment管理最为核心的工作。它有它自身的状态机,而它的状态,能够理解为与Activity本身基本同步。
在Fm里面维护自己的一个状态,当你导入一个Fragment的时候,Fm的目的,就是为了让Fragment和自己的状态基本保持一致.
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(); } } } ... } }
我们看到,FragmentManager的每一次状态变更,都会引起mActive里面的Fragment的状态变更。而mActive是全部纳入FragmentManager管理的Fragment容器。我们来看一下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.
能够看出实际上,你的状态越靠后你的状态值越大,实际上在Fm的管理中,也巧妙的用到了这一点。
if (f.mState < newState) { ... } else { ... }
对于f.mState<newState能够理解为创造的过程。同一时候我们也能找到我们上一篇文章的问题的答案:
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; } }
f.mFromLayout代表的是你这个Fragment的生成是否是从layout.xml文件里生成的。而它的View的生成是调用performCreateView来生成的。
View performCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { if (mChildFragmentManager != null) { mChildFragmentManager.noteStateNotSaved(); } return onCreateView(inflater, container, savedInstanceState); }
对,这里就是我们很熟悉的onCreateView回调的出处。
当然我们如今还是属于Fragment.INITIALIZING这个状态。但实际上,我们在调用Fragment的时候FragmentManageer已经进入了Create状态。也就是说newState參数应该是Create才对。
所以我们接着代码往下走:
case Fragment.CREATED: if (newState > Fragment.CREATED) { 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; }我们看到实际上这段代码是对FragmentManager状态是Create以上状态且Fragment的导入并非採用layout.xml方式导入的处理。这是为什么呢?由于在onCreate之后,基本上你的控件已经在Create状态的时候生成的差点儿相同了,你所要做的就是在生成的控件中找到Fragment相应的容器,然后装入你的控件。
同一时候,我们也看到了对Fragment的动画处理:
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; }而这样的动画的处理和參数的配置,我们留到后面讲到Fragment事务的时候再说。