選擇正確的 Fragment#commitXXX() 函數

轉自: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

commit() vs commitAllowingStateLoss()

大部分使用 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 的時候可能出現以下兩種狀態:

  1. 若是系統內存不足而且殺死了您的應用,當用戶從新打開您的 應用的時候,系統將會恢復您的應用到上面第二步的狀態,而 FragmentB 是不會顯示的。
  2. 若是系統沒有殺死您的應用,用戶則能夠看到 FragmentB。當 Activity 再次回到後臺的時候(onStop), FragmentB 的狀態纔會被保存起來。

Github 上有個示例項目 演示該狀況。在運行該示例的時候,若是打開開發者選項中的 「Don’t Keep Activities」 設置,則能夠用來顯示第一種狀況,FragmentB 的狀態徹底丟失了。 若是沒有打開 「Don’t Keep Activities」 選項,則能夠查看第二種狀況。

這兩個函數使用哪一個取決於您提交的 Fragment 和 該 Fragment 狀態是否重要,若是狀態丟失了也不要緊,則您可使用 commitAllowingStateLoss() 函數。

commit(), commitNow(), 和 executePendingTransactions()

其餘版本的 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() 的狀況是同樣的。

最後來總結下該如何選擇這些函數:

  • 若是你須要同步提交 Fragment 而且無需添加到 堆棧 中,則使用 commitNow()。 Support 庫中在 FragmentPagerAdapter 中使用這個函數,來確保更新 Adapter 的時候 正確的頁面被添加和刪除了。通常來講,只要不添加到堆棧中,均可以使用這個函數來提交。
  • 若是執行了屢次提交,而且不須要是同步的,或者把每次提交都添加到 堆棧 中,那麼就使用 commit()。
  • 若是 您須要把屢次提交操做的同一個時間點一塊兒執行,則使用 executePendingTransactions()
相關文章
相關標籤/搜索