FragmentTransaction的commit和commitAllowingStateLoss的區別

來源:互聯網
上載者:User

標籤:android開發   fragment   fragmenttransaction   commit   commitallowingstatel   

1、什麼是FragmentTransaction?

使用Fragment時,可以通過使用者互動來執行一些動作,比如增加、移除、替換等。

所有這些改變構成一個集合,這個集合被叫做一個transaction。

可以調用FragmentTransaction中的方法來處理這個transaction,並且可以將transaction存進由activity管理的back stack中,這樣使用者就可以進行fragment變化的後援動作。

可以這樣得到FragmentTransaction類的執行個體:

FragmentManager  mFragmentManager = getSupportFragmentManager();FragmentTransaction  mFragmentTransaction = mFragmentManager.beginTransaction();

2、commit和executePendingTransactions的區別用add(), remove(), replace()方法,把所有需要的變化加進去,然後調用commit()方法,將這些變化應用。
在commit()方法之前,你可以調用addToBackStack(),把這個transaction加入back stack中去,這個back stack是由activity管理的,當使用者按返回鍵時,就會回到上一個fragment的狀態。
你只能在activity儲存它的狀態(當使用者要離開activity時)之前調用commit(),如果在儲存狀態之後調用commit(),將會拋出一個異常。
這是因為當activity再次被恢複時commit之後的狀態將丟失。如果丟失也沒關係,那麼使用commitAllowingStateLoss()方法。
3、問什麼在儲存狀態之後調用commit會報異常?我們查看Android源碼發現FragmentManager和FragmentTransaction是一個虛類
那他們在activity中的執行個體化代碼是如何處理的呢?
首先是getSupportFragmentManager的方法
/**     * Return the FragmentManager for interacting with fragments associated     * with this activity.     */    public FragmentManager getSupportFragmentManager() {        return mFragments;    }


尋找到mFragments。
final FragmentManagerImpl mFragments = new FragmentManagerImpl();
我們發現FragmentManagerImpl是繼承於FragmentManager的一個實體類
/** * Container for fragments associated with an activity. */final class FragmentManagerImpl extends FragmentManager {        ........    @Override    public FragmentTransaction beginTransaction() {        return new BackStackRecord(this);    }    ........    }


為了簡便我們刪除了一些不要的代碼只留下關鍵的方法。
通過這段代碼,我們可以查看到beginTransaction方法實際返回的是一個繼承於FragmentTransaction的BackStackRecord類
我們來查看BackStackRecord的代碼,查看他的用法
/** * @hide Entry of an operation on the fragment back stack. */final class BackStackRecord extends FragmentTransaction implements        FragmentManager.BackStackEntry, Runnable {..........public int commit() {        return commitInternal(false);    }    public int commitAllowingStateLoss() {        return commitInternal(true);    }int commitInternal(boolean allowStateLoss) {        if (mCommitted) throw new IllegalStateException("commit already called");        if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Commit: " + this);        mCommitted = true;        if (mAddToBackStack) {            mIndex = mManager.allocBackStackIndex(this);        } else {            mIndex = -1;        }        mManager.enqueueAction(this, allowStateLoss);        return mIndex;    }..........}


繞了大半天,終於找到commit方法和commitAllowingStateLoss方法,他們都同時調用了commitInternal方法,只是傳的參數略有不同,一個是true,一個是false。我們發現在執行這個方法之前會首先對mCommitted進行判斷,根據代碼語義我們可以知道mCommitted就是是否已經commit的意思
最後,commitInternal調用了mManager.enqueueAction的方法。讓我們回到FragmentManager,看這個方法是如何操作的。我們找到這個方法。
/** * @hide Entry of an operation on the fragment back stack. */final class BackStackRecord extends FragmentTransaction implements        FragmentManager.BackStackEntry, Runnable {..........public int commit() {        return commitInternal(false);    }    public int commitAllowingStateLoss() {        return commitInternal(true);    }int commitInternal(boolean allowStateLoss) {        if (mCommitted) throw new IllegalStateException("commit already called");        if (FragmentManagerImpl.DEBUG) Log.v(TAG, "Commit: " + this);        mCommitted = true;        if (mAddToBackStack) {            mIndex = mManager.allocBackStackIndex(this);        } else {            mIndex = -1;        }        mManager.enqueueAction(this, allowStateLoss);        return mIndex;    }..........}


經分析後,我們可以發現,此方法在對 commit和commitAllowingStateLoss的傳參進行判斷後,將任務扔進activity的線程隊列中。那這個兩個方法區別就在傳參判斷後的處理方法checkStateLoss,那接下來,讓我們查看一下checkStateLoss方法,看對參數進行判斷後,做了什麼樣的處理。
private void checkStateLoss() {        if (mStateSaved) {            throw new IllegalStateException(                    "Can not perform this action after onSaveInstanceState");        }        if (mNoTransactionsBecause != null) {            throw new IllegalStateException(                    "Can not perform this action inside of " + mNoTransactionsBecause);        }    }


ok,到這裡,真相總算大明,當使用commit方法時,系統將進行狀態判斷,如果狀態(mStateSaved)已經儲存,將發生"Can not perform this action after onSaveInstanceState"錯誤。
如果mNoTransactionsBecause已經存在,將發生"Can not perform this action inside of " + mNoTransactionsBecause錯誤。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.