Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android]Fragment源碼分析(三) 事務

[Android]Fragment源碼分析(三) 事務

編輯:關於Android編程

Fragment管理中,不得不談到的就是它的事務管理,它的事務管理寫的非常的出彩。我們先引入一個簡單常用的Fragment事務管理代碼片段:

            FragmentTransaction ft = this.getSupportFragmentManager().beginTransaction();
            ft.add(R.id.fragmentContainer, fragment, "tag");
            ft.addToBackStack("tag");
            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.
     *
     * 

* 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. *

*/ 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();
            }
            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();
        }
        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管理的部分源碼。





  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved