Android commit 和 commitAllowingStateLoss 的區(qū)別

1615230-60be89c602040f87.jpg

fragment 基本上是每個(gè)項(xiàng)目都會(huì)用到彤钟,一般我們會(huì)這么寫:

    getSupportFragmentManager()
            .beginTransaction()
            .add(R.id.fragment_container, new MyFragment())
            .commit();

但是有時(shí)候會(huì)報(bào)如下錯(cuò)誤信息:

    Caused by: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState

意思就是說我們不能在調(diào)用onSaveInstanceState進(jìn)行commit操作来候。網(wǎng)上的解決辦法是使用commitAllowingStateLoss替換commit。確實(shí)是不報(bào)錯(cuò)了逸雹,但是為什么呢营搅?

來,開始我們的偵探之旅吧0鹪摇(有點(diǎn)繞转质,請(qǐng)一步步往下看)

首先找到FragmentTransaction類。

    public abstract class FragmentTransaction {
        public abstract int commit();
        public abstract int commitAllowingStateLoss();
    }

原來commitcommitAllowingStateLoss是抽象方法帖世。繼續(xù)往下找休蟹。

    final class BackStackRecord extends FragmentTransaction implements
            FragmentManager.BackStackEntry, FragmentManagerImpl.OpGenerator {
        @Override
        public int commit() {
            return commitInternal(false);
        }

        @Override
        public int commitAllowingStateLoss() {
            return commitInternal(true);
        }
    }

發(fā)現(xiàn)BackStackRecord類繼承了FragmentTransaction。可以看出赂弓,不同之處只有commitInternal的參數(shù)绑榴。感覺離真相又近了一步,繼續(xù)往下看:

    int commitInternal(boolean allowStateLoss) {    
        // ...不顯示無關(guān)代碼
        mManager.enqueueAction(this, allowStateLoss);
        return mIndex;
    }

commitInternal方法內(nèi)盈魁,只有mManager.enqueueAction(this, allowStateLoss);使用了該布爾值參數(shù)翔怎。離真相還差一點(diǎn)了,繼續(xù)推測:

    public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
        if (!allowStateLoss) {
            checkStateLoss();
        }
        synchronized (this) {
            if (mDestroyed || mHost == null) {
                if (allowStateLoss) {
                    // This FragmentManager isn't attached, so drop the entire transaction.
                    return;
                }
                throw new IllegalStateException("Activity has been destroyed");
            }
            // ...無關(guān)代碼
        }
    }

有了突破性進(jìn)展杨耙!此處對(duì)allowStateLoss值進(jìn)行了判斷赤套。checkStateLoss按照命名意思是校驗(yàn)狀態(tài)。離真相僅剩一步了珊膜!

    private void checkStateLoss() {
        if (isStateSaved()) {
            throw new IllegalStateException(
                    "Can not perform this action after onSaveInstanceState");
        }
        if (mNoTransactionsBecause != null) {
            throw new IllegalStateException(
                    "Can not perform this action inside of " + mNoTransactionsBecause);
        }
    }

    @Override
    public boolean isStateSaved() {
        // See saveAllState() for the explanation of this.  We do this for
        // all platform versions, to keep our behavior more consistent between
        // them.
        return mStateSaved || mStopped;
    }

這里會(huì)拋出異常信息容握,明顯就是文章開頭碰到的異常錯(cuò)誤信息!isStateSaved()方法也一同顯示了车柠。到了此時(shí)剔氏,可以明白commit是會(huì)對(duì)狀態(tài)進(jìn)行檢測,并拋出異常堪遂;而commitAllowingStateLoss方法只是不進(jìn)行狀態(tài)檢測,因此不會(huì)拋出異常萌庆。這明顯是有點(diǎn)逃避問題溶褪,那么這個(gè)狀態(tài)是什么判斷而得出的呢?

    Parcelable saveAllState() {
        // ...無關(guān)代碼
        mStateSaved = true;
        // ...無關(guān)代碼
    }

我們主要看mStateSaved變量践险。在saveAllState 方法內(nèi)猿妈,把mStateSaved賦值為 true。有意思的是saveAllState是在ActivityFragmentActivity內(nèi)的onSaveInstanceState方法調(diào)用的巍虫。

總結(jié):

有點(diǎn)繞~最后在此理順整體思路:在ActivityFragmentActivity內(nèi)的onSaveInstanceState方法保存了fragment的狀態(tài)彭则。在onSaveInstanceState方法后調(diào)用commitcommitAllowingStateLoss會(huì)引起一種問題:因內(nèi)存不足而把不顯示在前臺(tái)的 activity (帶有 fragment)銷毀,之后用戶再回到此 activity 頁面時(shí)占遥,是會(huì)丟失在onSaveInstanceState后調(diào)用commit方法提交的頁面狀態(tài)信息俯抖!
不同的只是調(diào)用commit會(huì)報(bào)錯(cuò),調(diào)用commitAllowingStateLoss不報(bào)錯(cuò)(睜一只眼閉一只眼)瓦胎。

谷歌在commitAllowingStateLoss方法的注釋上也寫明芬萍,調(diào)用此方法會(huì)有丟失頁面狀態(tài)信息的風(fēng)險(xiǎn)搔啊。

Like {@link #commit} but allows the commit to be executed after an
activity's state is saved. This is dangerous because the commit can
be lost if the activity needs to later be restored from its state, so
this should only be used for cases where it is okay for the UI state
to change unexpectedly on the user.

  1. 一般情況下柬祠,盡量提早調(diào)用 commit 方法,比如說onCreate()负芋;
  2. 異步回調(diào)中避免使用commit漫蛔;
  3. 不得已的情況,可以使用commitAllowingStateLoss替代commit。畢竟報(bào)錯(cuò)奔潰莽龟,比頁面狀態(tài)信息丟失更嚴(yán)重蠕嫁;

推薦:

Android commit 和 commitAllowingStateLoss 區(qū)別及應(yīng)用場景

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市轧房,隨后出現(xiàn)的幾起案子拌阴,更是在濱河造成了極大的恐慌,老刑警劉巖奶镶,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件迟赃,死亡現(xiàn)場離奇詭異,居然都是意外死亡厂镇,警方通過查閱死者的電腦和手機(jī)纤壁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來捺信,“玉大人酌媒,你說我怎么就攤上這事∑浚” “怎么了秒咨?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長掌挚。 經(jīng)常有香客問我雨席,道長,這世上最難降的妖魔是什么吠式? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任陡厘,我火速辦了婚禮,結(jié)果婚禮上特占,老公的妹妹穿的比我還像新娘糙置。我一直安慰自己,他們只是感情好是目,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布谤饭。 她就那樣靜靜地躺著,像睡著了一般懊纳。 火紅的嫁衣襯著肌膚如雪网持。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天长踊,我揣著相機(jī)與錄音功舀,去河邊找鬼。 笑死身弊,一個(gè)胖子當(dāng)著我的面吹牛辟汰,可吹牛的內(nèi)容都是我干的列敲。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼帖汞,長吁一口氣:“原來是場噩夢啊……” “哼戴而!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起翩蘸,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤所意,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后催首,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扶踊,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年郎任,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秧耗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡舶治,死狀恐怖分井,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情霉猛,我是刑警寧澤尺锚,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站惜浅,受9級(jí)特大地震影響瘫辩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赡矢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一杭朱、第九天 我趴在偏房一處隱蔽的房頂上張望阅仔。 院中可真熱鬧吹散,春花似錦、人聲如沸八酒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽羞迷。三九已至界轩,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間衔瓮,已是汗流浹背浊猾。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留热鞍,地道東北人葫慎。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓衔彻,卻偏偏與公主長得像,于是被迫代替她去往敵國和親偷办。 傳聞我的和親對(duì)象是個(gè)殘疾皇子艰额,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容