当前位置: 代码迷 >> Android >> [Android]Fragment源码分析(2) 状态
  详细解决方案

[Android]Fragment源码分析(2) 状态

热度:419   发布时间:2016-04-28 04:24:27.0
[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事务的时候再说。



  相关解决方案