• [Android]Fragment源代码分析(三) 事务


    Fragment管理中,不得不谈到的就是它的事务管理,它的事务管理写的很的出彩。我们先引入一个简单经常使用的Fragment事务管理代码片段:

                FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
                ft.add(R.id.fragmentContainer, fragment, "tag");
                ft.addToBackStack("<span style="font-family: Arial, Helvetica, sans-serif;">tag</span><span style="font-family: Arial, Helvetica, sans-serif;">");</span>
                ft.commitAllowingStateLoss();

    这段代码运行过后,就能够往fragmentContainer控件中增加Fragment的内部持有控件。

    上一讲我们说到Fragment通过状态机的变更来生成内部的mView。当你使用的是非from layout.xml方式的时候,它会在Fragment.CREATED状态下搜索container相应的控件然后将mView增加到这个父控件中。

    那么这个事务又在这里面承担什么样的作用呢?

    我们先来看Manager.beginTransaction这种方法的返回值:

    /**
         * Start a series of edit operations on the Fragments associated with this
         * FragmentManager.
         *
         * <p>
         * Note: A fragment transaction can only be created/committed prior to an
         * activity saving its state. If you try to commit a transaction after
         * {@link FragmentActivity#onSaveInstanceState
         * FragmentActivity.onSaveInstanceState()} (and prior to a following
         * {@link FragmentActivity#onStart FragmentActivity.onStart} or
         * {@link FragmentActivity#onResume FragmentActivity.onResume()}, you will
         * get an error. This is because the framework takes care of saving your
         * current fragments in the state, and if changes are made after the state
         * is saved then they will be lost.
         * </p>
         */
        public abstract FragmentTransaction beginTransaction();
    在Fragment的管理中FragmentManager的实现类是FragmentManagerImpl,当然这也是Android一贯的命名方式;

    FragmentManagerImpl.java:
    @Override
        public FragmentTransaction beginTransaction() {
            return new BackStackRecord(this);
        }

    FragmentManager通过返回一个叫做BackStackRecord的对象完毕事务处理。抛开Android本身,我们对于事务的理解主要源于数据库,也就是一种批量性的操作,记录下你的操作集合,然后一次性处理,保证事务处理时候的安全性和高效性。FragmentManager看待事务的观点也基本一致,BackStackRecord的核心方法是addOp(Op):

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

    我们看到,对于BackStackRecord对操作处理的组织是採用"迭代器"的模式,每个操作被记录成为Op对象,又能够当作"备忘录"模式来看待。而对于加入操作的入口:

    public FragmentTransaction add(Fragment fragment, String tag) {
            doAddOp(0, fragment, tag, OP_ADD);
            return this;
        }
    
        public FragmentTransaction add(int containerViewId, Fragment fragment) {
            doAddOp(containerViewId, fragment, null, OP_ADD);
            return this;
        }
    
        public FragmentTransaction add(int containerViewId, Fragment fragment, String tag) {
            doAddOp(containerViewId, fragment, tag, OP_ADD);
            return this;
        }

    是採用"Builder"的方式来组织。

    文章開始我已经提到了,Fragment的事务管理是比較出彩的代码,单纯的事务採用了至少三套模式来组织,并且组织起来丝毫没有感觉。

    当然Fragment带给我们的惊喜还不仅限于此。我们总上面的代码片段能够看出,实际上,通过事务类BackStackRecord生成Op对象实际上在复制BackStackRecord的属性,所以当我们分析每个Op里面的数据的时候,能够直接用BackStackRecord中的属性映射。

        int mNumOp;//Op数量
        int mEnterAnim;//进入动画
        int mExitAnim;//退出动画
        int mPopEnterAnim;//弹出进入动画
        int mPopExitAnim;//弹出退出动画
        int mTransition;//转场动画
        int mTransitionStyle;
        boolean mAddToBackStack;//是否增加到BackStack中

    Op本身属于Command模式,它的Command列表各自是:

        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;

    也许你也已经看出来了,没错,Op的属性就是作为Command的操作数。在BackStackRecord进行Commit了之后,BackStackRecord会将自己纳入FragmentManagerImpl的命令队列中处理。

    每个处理单元用于处理各自的Op操作。

    我们来看下代码:

    BackStackRecord.java:
    int commitInternal(boolean allowStateLoss) {
            if (mCommitted) throw new IllegalStateException("commit already called");
            mCommitted = true;
            if (mAddToBackStack) {
                mIndex = mManager.allocBackStackIndex(this);
            } else {
                mIndex = -1;
            }
            mManager.enqueueAction(this, allowStateLoss);
            return mIndex;
        }

    BackStackRecord在提交的时候会将自己提交到mManager的Action队列中去。

    而这样的Action队列的处理能够在随意线程中进行

    FragmentManager.java:
     
    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);
                }
            }
        }

    我们看到实际上Action是被mExecCommit命令所运行,而它,将回调你所提交的BackStackRecord的run方法。

    BackStackRecord.java:
           Op op = mHead;
            while (op != null) {
                 ...
            }

    我们看到,命令是以迭代器的方式在循环执行。

    不同的命令将对Fragment有不同的状态变更操作,举个简单的样例:

    Op.java:
    
    case OP_ADD: {
                        Fragment f = op.fragment;
                        f.mNextAnim = op.enterAnim;
                        mManager.addFragment(f, false);
                    } break;

    当我们须要Add一个Fragment的时候,Op将调用FragmentManager的addFragment方法

    FragmentManager.java:
    public void addFragment(Fragment fragment, boolean moveToStateNow) {
            if (mAdded == null) {
                mAdded = new ArrayList<Fragment>();
            }
            makeActive(fragment);
            if (!fragment.mDetached) {
                if (mAdded.contains(fragment)) {
                    throw new IllegalStateException("Fragment already added: "
                            + fragment);
                }
                mAdded.add(fragment);
                fragment.mAdded = true;
                fragment.mRemoving = false;
                if (fragment.mHasMenu && fragment.mMenuVisible) {
                    mNeedMenuInvalidate = true;
                }
                if (moveToStateNow) {
                    moveToState(fragment);
                }
            }
        }

    FragmentManager会将它先增加到自己的mAdded队列中去,然后通过调用moveToState方法来改变Fragment状态保证状态上的一致性。而这一部分,就是我们上一部分讲的内容,我们不再赘述。这样Fragment通过这样的优雅的方式就实现了事务的处理。

    下一篇,我将给大家讲述Fragment关于Stack管理的部分源代码。





  • 相关阅读:
    扩展欧几里得算法
    poj-3094-quicksum
    (floyd)佛洛伊德算法
    poj-3660-cows contest(不懂待定)
    poj-1056-IMMEDIATE DECODABILITY(字典)
    delete与delete[]的区别
    poj-1046-color me less
    SqlParameter 使用
    VS2010中出现无法嵌入互操作类型(转)
    fastreport代码转
  • 原文地址:https://www.cnblogs.com/mthoutai/p/7105766.html
Copyright © 2020-2023  润新知