轉自:html
http://www.tuicool.com/articles/q6R7niijava
最新版本(v24.0.0)的 Support v4 庫中的 FragmentTransaction 添加了 commitNow() 和 commitNowAllowingStateLoss () 兩個函數,這樣 提交一個 Fragment 就有以下4個函數能夠選擇:android
– commit()git
– commitAllowingStateLoss()github
– commitNow()app
– commitNowAllowingStateLoss()函數
另外,在使用 Fragment 的過程當中,可能您已經使用過了 executePendingTransactions() 這個函數了。ui
下面來深刻分析下每一個函數是幹啥用的,你應該使用哪一個函數。this
大部分使用 Fragment 的開發者可能都遇到過以下的異常:線程
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
Alex Lockwood 寫過一篇文章來詳細解釋爲什麼會出現該異常。可是開發者更多的是想知道他們的應用出現了該問題意味着什麼?
commit() 和 commitAllowingStateLoss() 的實現幾乎是同樣的。惟一的區別就是在調用 commit() 的時候 FragmentManager 會檢查是否已經保存了其狀態,若是狀態已經保存了,則就拋出 IllegalStateException 異常。
那麼,在 onSaveInstanceState() 函數執行之後,您調用 commitAllowingStateLoss() 會丟失那些狀態呢? 答案就是你可能丟失 FragmentManager 的狀態,這裏麪包含在 onSaveInstanceState() 執行以後添加和刪除的 Fragment。
例如:
1. 當前您的 Activity 在顯示 FragmentA
2. 您的 Activity 被切換到後臺了((onStop() 和 onSaveInstanceState() 函數被調用了)
3. 這個時候您的 Activity 的邏輯發生了一些變化,您使用 FragmentB 替換了 FragmentA 並調用了 commitAllowingStateLoss() 函數來提交這個變化。
這個時候,當用戶再次切回您的 Activity 的時候可能出現以下兩種狀態:
Github 上有個示例項目 演示該狀況。在運行該示例的時候,若是打開開發者選項中的 「Don’t Keep Activities」 設置,則能夠用來顯示第一種狀況,FragmentB 的狀態徹底丟失了。 若是沒有打開 「Don’t Keep Activities」 選項,則能夠查看第二種狀況。
這兩個函數使用哪一個取決於您提交的 Fragment 和 該 Fragment 狀態是否重要,若是狀態丟失了也不要緊,則您可使用 commitAllowingStateLoss() 函數。
其餘版本的 commit() 指定了提交發生的時機。 commit() 的文檔有以下說明:
安排一個針對該事務的提交。提交併無馬上發生,會安排到在主線程下次準備好的時候來執行。 (Schedules a commit of this transaction. The commit does not happen immediately; it will be scheduled as work on the main thread to be done the next time that thread is ready.)
上面文檔說明的意思是,你能夠同時執行屢次提交,這些提交都沒有馬上執行,知道下次主線程準備好了才一塊兒執行這些提交的 Fragment。這些針對 Fragment 的提交操做包含 添加、刪除、替換以及經過函數 popBackStack() 來返回前一個 Fragment。
有時候,您須要針對 Fragment 的操做馬上執行。以前都是經過在調用函數 commit() 後調用 executePendingTransactions() 來實現的。
在 24.0.0 版本的 Support 庫中添加了 commitNow() 函數來更好的支持這種操做。commitNow() 只同步的執行當前的提交操做,而 executePendingTransactions() 則會執行全部等得執行的操做。 commitNow() 能夠避免您執行以前提交的可是無需馬上執行的操做。
commitNow() 有個限制,沒法把當前提交的 Fragment 添加到堆棧(back stack)中。假設有以下的狀況:
經過 commit() 函數把 Fragment A 添加到堆棧中,而後馬上使用 commitNow() 把另一個 Fragment B 添加到堆棧中,這樣當前的堆棧應該是何種狀態? 是 Fragment A 在前面仍是 Fragment B 在前面呢?
popBackStack() 和 popBackStackImmediate() 與 commit() 和 commitNow() 的狀況是同樣的。
最後來總結下該如何選擇這些函數: