zoukankan      html  css  js  c++  java
  • [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事务的时候再说。





  • 相关阅读:
    常用工具
    H5页面验收流程及性能验收标准
    埋点数据测试
    提高效率的必备工具
    移动APP安全测试
    Response响应相关
    AES加密解密
    Requests模块
    爬虫入门
    【CMDB】API传输验证
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5304623.html
Copyright © 2011-2022 走看看