commit(), commitNow()和commitAllowingStateLoss()


關於FragmentTransaction的各種提交方法: commit(),commitAllowingStateLoss(),commitNow()commitNowAllowingStateLoss().
作者Bryan Herbst發了一個blog The many flavors of commit()討論這幾個方法的特點和用途.
下文是中文摘要.

FragmentTransaction的提交方法

support library的FragmentTransaction現在提供了四種不同的方法來commit一個transaction:
commit()
commitAllowingStateLoss()
commitNow()
commitNowAllowingStateLoss()

這篇文章分析了這四個方法的不同.

commit() vs commitAllowingStateLoss()

commit()提交有時候會遇到IllegalStateException, 說你在onSaveInstanceState()之后提交, 這里有另一個文章很好地分析了這個問題:Fragment Transactions & Activity State Loss
commit()commitAllowingStateLoss()在實現上唯一的不同就是當你調用commit()的時候, FragmentManger會檢查是否已經存儲了它自己的狀態, 如果已經存了, 就拋出IllegalStateException.
那么如果你調用的是commitAllowingStateLoss(), 並且是在onSaveInstanceState()之后, 你可能會丟失掉什么狀態呢?
答案是你可能會丟掉FragmentManager的狀態, 即save之后任何被添加或被移除的Fragments.
舉例說明:
1.在Activity里顯示一個FragmentA;
2.然后Activity被后台, onStop()onSaveInstanceState()被調用;
3.在某個事件觸發下, 你用FragmentB replace FragmentA , 使用的是 commitAllowingStateLoss().
這時候, 用戶再返回應用, 可能會有兩種情況發生:
1.如果系統殺死了你的activity, 你的activity將會重建, 使用了上述步驟2保存的狀態, 所以A會顯示, B不會顯示;
2.如果系統沒有殺死你的activity, 它會被提到前台, FragmentB就會顯示出來, 到下次Activity stop的時候, 這個包含了B的狀態就會被存下來.
(上述測試可以利用開發者選項中的”Don’t Keep Activities”選項).
那么你要選擇哪一種呢? 這就取決於你提交的是什么, 還有你是否能接受丟失.

commit(), commitNow() 和 executePendingTransactions()

使用commit()的時候, 一旦調用, 這個commit並不是立即執行的, 它會被發送到主線程的任務隊列當中去, 當主線程准備好執行它的時候執行.
popBackStack()的工作也是這樣, 發送到主線程任務隊列中去. 也即說它們都是異步的.

但是有時候你希望你的操作是立即執行的, 之前的開發者會在commit()調用之后加上 executePendingTransactions()來保證立即執行, 即變異步為同步.
support library從v24.0.0開始提供了 commitNow()方法, 之前用executePendingTransactions()會將所有pending在隊列中還有你新提交的transactions都執行了, 而commitNow()將只會執行你當前要提交的transaction. 所以commitNow()避免你會不小心執行了那些你可能並不想執行的transactions.

但是你不能對要加在back stack中的transaction使用commitNow(), 即addToBackStack()commitNow()不能同時使用.
為什么呢?
想想一下, 如果你有一個提交使用了commit(), 緊接着又有另一個提交使用了commitNow(), 兩個都想加入back stack, 那back stack會變成什么樣呢? 到底是哪個transaction在上, 哪個在下? 答案將是一種不確定的狀態, 因為系統並沒有提供任何保證來確保順序, 所以系統決定干脆不支持這個操作.

前面提過popBackStack()是異步的, 所以它同樣也有一個同步的兄弟popBackStackImmediate().

所以實際應用的時候怎么選擇呢?

  1. 如果你需要同步的操作, 並且你不需要加到back stack里, 使用commitNow().
    support library在FragmentPagerAdapter里就使用了commitNow()來保證在更新結束的時候, 正確的頁面被加上或移除.
  2. 如果你操作很多transactions, 並且不需要同步, 或者你需要把transactions加在back stack里, 那就使用commit().
  3. 如果你希望在某一個指定的點, 確保所有的transactions都被執行, 那么使用executePendingTransactions().

Reference

這是Android Weekly #220的一篇文章, 我在做這期筆記的時候覺得這個寫得很好, 所以決定單獨拿出來說一說. 這期整體的筆記稍后推出, 敬請期待哇.
原文The many flavors of commit()


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM