在公司的專案內,我們使用了大量的Fragment來達到頁面切換的效果。為了呈現designer設計好的操作流程,我們會在不同的lifecycle callback裡面做相關的設定。由於預期lifecycle callback的順序是固定的,所以這些設定彼此之間有前後關係。
What happened
升級support library版本至25.1.0後,很多頁面呈現時出現不少錯誤,經過研究後發現是lifecycle callback的順序已經改變,導致設定的順序顛倒。
這影響的範圍有兩個地方:
FragmentTransaction.replace()
FragmentManager.popBackStack()
replace()
為了減少層次,讓使用者可以更方便的退回首頁,我們使用FragmentTransaction.replace()
替換Fragment,在25.1.0以前,lifecycle callback順序如下:
FragmentA.onPause() |
而25.1.0則是:
FragmentB.onStart() |
popBackStack()
用popBackStack()
可以方便的將最上層的Fragment退出。
在25.1.0以前,lifecycle callback順序如下:
Fragment B: onStop() |
而25.1.0則是:
Fragment A: onStart() |
Summary
退一步來看,可以發現其實前後版本是在不同的大前提下
- 25.1.0以前:先退出前一個Fragment。
- 25.1.0以後:先加入後一個Fragment。
Why
依照官方說法,順序變動是預期中的更動,為了效能上的優化。
Solution
官方在Issue 37130220、37130329提出解法,不過依照討論內容,可知不同的版本有些不同,詳列如下:
25.1.0
由於效能優化預設是打開,為保持彈性,可以透過FragmentTransaction.setAllowOptimization(false)
關閉。如此replace()
的lifecycle callback順序就會和以前相同,但popBackStack()
依然無法還原。
25.1.1
這版開始,優化功能預設更改為關閉,所有行為皆還原到25.1.0之前。不過依然可以透過FragmentTransaction.setAllowOptimization(false)
打開。
25.2.0
在Issue 37130220中有人提到相同錯誤又再次出現,所以如果有疑慮應該要跳過此版。
25.3.0
此版應是穩定版本,在此版release之後就沒有人留言發現問題。
26.1.0
此版將setAllowOptimization()
更名成setReorderingAllowed()
。
Summary
要不直接升級26.1.0,使用setReorderingAllowed()
將lifecycle callback順序返回舊版順序,不然就停在25.1.0之前。