美文网首页
Android-Fragment简要分析

Android-Fragment简要分析

作者: wyonxue | 来源:发表于2018-03-06 10:42 被阅读0次

    注意:文章对Fragment源码的分析基于support v4的Fragment包,版本号为25.3.1

    Fragment相关类UML图

    1008428-b84d45b1ba19d73d.jpg

    support包中对负责管理Fragment生命是FragmentActivity,v7包的AppCompatActivity也是继承于它。
    FragmentActivity管理Fragment是通过它内部mFragments的变量,mFragments类型为FragmentController.

    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    

    FragmentActivity传递自身生命状态、状态保存、恢复都是通过调用mFragments相应的方法进行处理;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        mFragments.attachHost(null /*parent*/);
     
        super.onCreate(savedInstanceState);
     
        //...
        mFragments.restoreAllState(p, nc != null ? nc.fragments : null);
     
        //...
        mFragments.dispatchCreate();
    }
     
    public FragmentManager getSupportFragmentManager() {
            return mFragments.getSupportFragmentManager();
    }
    

    而FragmentController本身只是简单的将相应请求转发给FragmentManagerImpl,只是起到了桥梁沟通作用。

    FragmentActivity创建mFragments时传递了一个HostCallbacks内部类实例,这个callback对象给Fragment提供了获取Context,启动Activity的能力。

    Fragment

    Fragment主要是由Attr、View、State构成,
    Attr:固有属性,Fragment基本信息,基本不会随生命周期变化。

    Bundle mArguments;  //构造参数
    boolean mFromLayout; //是否从layout文件中创建
    String mTag;
    ...
    

    View:Fragment管理View所依赖的相关成员变量。

    // The parent container of the fragment after dynamically added to UI.
    ViewGroup mContainer;
     
    // The View generated for this fragment.
    View mView;
     
    // The real inner view that will save/restore state.
    View mInnerView;
    

    State:Fragment的状态,管理Fragment的显示、生命周期。

    int mState = INITIALIZING; //生命周期状态
    boolean mAdded; //是否被添加
    boolean mRemoving; //是否被移除
    boolean mHidden;// 是否被隐藏
    boolean mDetached; //是否已经分离
     
    // mState取值如下
    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.
    

    Fragment的生命周期方法,onAttach, onCreate, onCreateView...都是在mState状态变化中进行回调的。

    Fragment的事务:FragmentTransaction、BackStackRecord

    添加一个Fragment,我们一般使用如下代码:

    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
    transaction.add(R.id.contaniner, fragment);
    transaction.commit();
    

    FragmentTransaction表示一个事务,提供了如add、remove、attach、detach、show、hide、replace等接口操控Fragment。它的具体实现类是BackStackRecord,它的接口实现如下:

    @Override
    public FragmentTransaction add(Fragment fragment, String tag) {
        doAddOp(0, fragment, tag, OP_ADD);
        return this;
    }
     
    private void doAddOp(int containerViewId, Fragment fragment, String tag, int opcmd) {
        ...
        Op op = new Op();
        op.cmd = opcmd;
        op.fragment = fragment;
        addOp(op);
    }
     
    void addOp(Op op) {
        mOps.add(op);
        op.enterAnim = mEnterAnim;
        op.exitAnim = mExitAnim;
        op.popEnterAnim = mPopEnterAnim;
        op.popExitAnim = mPopExitAnim;
    }
     
    @Override
    public FragmentTransaction remove(Fragment fragment) {
        Op op = new Op();
        op.cmd = OP_REMOVE;
        op.fragment = fragment;
        addOp(op);
        return this;
    }
    ...
    

    可以看到我们调用的add、remove等方法最后都是生成一个Op对象保存在mOps列表中,Op是Operator简写表示操作,Op的cmd属性则区分操作的类型,cmd的值取如下几种:

    static final int OP_NULL = 0;
    static final int OP_ADD = 1;
    static final int OP_REPLACE = 2;
    static final int OP_REMOVE = 3;
    static final int OP_HIDE = 4;
    static final int OP_SHOW = 5;
    static final int OP_DETACH = 6;
    static final int OP_ATTACH = 7;
    

    上面操作完毕后,最后是commit事务了

    @Override
    public int commit() {
        return commitInternal(false);
    }
     
    @Override
    public int commitAllowingStateLoss() {
        return commitInternal(true);
    }
     
    @Override
    public void commitNow() {
        ...
        // 直接开始执行事务
        mManager.execSingleAction(this, false);
    }
     
    @Override
    public void commitNowAllowingStateLoss() {
        ...
        // 直接开始执行事务
        mManager.execSingleAction(this, true);
    }
     
    int commitInternal(boolean allowStateLoss) {
        ...
        // 事务入对象,等待下一个Handler回调执行
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }
    

    *AllowingStateLoss表示是否允许状态丢失,如果不允许但是当前Activity状态已经触发保存了调用会抛出异常;commit、commitNow的区别则是提交事务等待下个主线程Handler回调执行还是立即执行,除了执行时机不一样外,两者最后触发的事务执行逻辑是一样的。

    事务执行逻辑依然在BackStackRecord中:

    void executeOps() {
        final int numOps = mOps.size();
        for (int opNum = 0; opNum < numOps; opNum++) {
            final Op op = mOps.get(opNum);
            final Fragment f = op.fragment;
            f.setNextTransition(mTransition, mTransitionStyle);
            switch (op.cmd) {
                case OP_ADD:
                    f.setNextAnim(op.enterAnim);
                    mManager.addFragment(f, false);
                    break;
                case OP_REMOVE:
                    f.setNextAnim(op.exitAnim);
                    mManager.removeFragment(f);
                    break;
                case OP_HIDE:
                    f.setNextAnim(op.exitAnim);
                    mManager.hideFragment(f);
                    break;
                case OP_SHOW:
                    f.setNextAnim(op.enterAnim);
                    mManager.showFragment(f);
                    break;
                case OP_DETACH:
                    f.setNextAnim(op.exitAnim);
                    mManager.detachFragment(f);
                    break;
                case OP_ATTACH:
                    f.setNextAnim(op.enterAnim);
                    mManager.attachFragment(f);
                    break;
                default:
                    throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
            }
            if (!mAllowOptimization && op.cmd != OP_ADD) {
                mManager.moveFragmentToExpectedState(f);
            }
        }
        if (!mAllowOptimization) {
            // Added fragments are added at the end to comply with prior behavior.
            mManager.moveToState(mManager.mCurState, true);
        }
    }
    

    执行逻辑是遍历所有添加的操作,执行相应的FragmentManage方法,最后将Fragment的状态移动的相应的状态。

    Fragment状态变迁:moveToState

    Fragment添加到FragmentMange中后,要将它移动到相应的状态,使Fragment正确的显示、交互。

    FragmentManage的成员变量mCurState存储着当前Activity状态对应的Fragment状态值,它的取值范围如同Fragment。Activity的状态发生变化时都会触发相应方法修改mCurState,并将所有的active 的Fragment移动到相应的状态上。

    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() {
        // See saveAllState() for the explanation of this.  We do this for
        // all platform versions, to keep our behavior more consistent between
        // them.
        mStateSaved = true;
     
        moveToState(Fragment.STOPPED, false);
    }
     
    public void dispatchReallyStop() {
        moveToState(Fragment.ACTIVITY_CREATED, false);
    }
     
    public void dispatchDestroyView() {
        moveToState(Fragment.CREATED, false);
    }
     
    public void dispatchDestroy() {
        mDestroyed = true;
        execPendingActions();
        moveToState(Fragment.INITIALIZING, false);
        mHost = null;
        mContainer = null;
        mParent = null;
    }
    

    FragmentManage的moveToState方法就负责了将自己管理的所有Fragment的状态移动到对应的状态上,当mCurState变化,或者Fragment操作触发都会调用该方法。

    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.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.
            ...
            switch (f.mState) {
                case Fragment.INITIALIZING:
                    ...
                case Fragment.CREATED:
                    if (newState > Fragment.CREATED) {
                       ...
                    }
                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.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();
                    }
                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) {
                       ...
                    }
                case Fragment.CREATED:
                    if (newState < Fragment.CREATED) {
                        ...
                    }
            }
        }
     
        ...
    }
    

    fragment的state取值,为前面提到的七中状态,其中最低值是INITIALIZING状态,代表fragment刚创建,还未被add, 最高状态值是RESUMED,代表fragment处于前台。 所以moveToState内部分两条线,状态跃升,和状态降低,里面各有一个switch判断,注意到switch里每个case都没有break,这意味着,状态可以持续变迁,比如从INITIALIZING,一直跃升到RESUMED,将每个case都走一遍,每次case语句内,都会改变state的值。

    Untitled.png

    Fragment状态保存、恢复

    主要实现代码是FragmentManageImpl的saveAllState()和restoreAllState()方法。

    FragmentActivity的onSaveInstance()方法中会间接调用FragmentManageImpl的saveAllState()方法,而onCreate(Bundle)中会间接调用restoreAllState()。在Fragment的onCreate(Bundle)等初始化生命方法中会传入保存状态的Bundle,以供开发者恢复存储的数据。而Fragment中view的状态的恢复则是在回调了onCreateView()后得到开发者返回的view,手动触发view状态的恢复:

    // FragmentManageImpl.class
    void moveToState(Fragment f, int newState, int transit, int transitionStyle,
                boolean keepActive) {
      ...
      if(f.mState < newState) { // 状态升
         ...
        switch(f.mState) {
          ...
          case Fragment.CREATED:
            ...
            f.mView = f.performCreateView(f.performGetLayoutInflater(
                                        f.mSavedFragmentState), container, f.mSavedFragmentState);
            ...
            f.performActivityCreated(f.mSavedFragmentState);
            ...
            if (f.mView != null) {
              f.restoreViewState(f.mSavedFragmentState);
            }
            f.mSavedFragmentState = null;
        }
        ...
      }
      ...
    }
    
    // Fragment.class
      final void restoreViewState(Bundle savedInstanceState) {
            if (mSavedViewState != null) {
                mInnerView.restoreHierarchyState(mSavedViewState);
                mSavedViewState = null;
            }
            mCalled = false;
            onViewStateRestored(savedInstanceState);
            if (!mCalled) {
                throw new SuperNotCalledException("Fragment " + this
                        + " did not call through to super.onViewStateRestored()");
            }
        }
    

    Fragment常见错误:

    可以参考:https://www.jianshu.com/p/d9143a92ad94

    getActivity空指针错误

    状态没保存、值丢失

    Can not perform this action after onSaveInstanceState异常

    Fragment类必须提供无参构造方法

    Fragment重叠显示异常

    其他

    Fragment中还有回退栈、动画、Android5.0中的共享元素及Activity动画、Fragment.retainInstance属性、LoaderManager、ChildFragmentManage等知识点这里先不讨论了。

    参考
    从源码角度剖析Fragment核心知识点

    相关文章

      网友评论

          本文标题:Android-Fragment简要分析

          本文链接:https://www.haomeiwen.com/subject/srdlfftx.html