Android 多個Fragment嵌套導致的三大BUG


Android有碎片化的問題,當然本文說的碎片化不是指的系統版本碎片化的問題,而是Fragment組件碎片化的問題。

很久之前,在Android 3.1系統發布的時候,Google推出了使用Fragment來更加容易地開發平板和手機應用,雖然Activity還是頁面結構的主體,但是卻可以在其基礎上使用多個Fragment來構建頁面,這些Fragment都是有各自的生命周期的。

最常見的是列表和詳情頁面使用Fragment,如果在手機設備上,這個兩個一般都是在獨立的Activity頁面中,但是在平板上這兩個Fragment往往都是嵌套在一個Activity中。

當然,在開發過程中,正常情況下都是沒有問題的。

1、特殊的Fragment

如果想要使用Fragment來開發應用並且適配低版本系統,必須要使用Google提供的Support Library(V4).

Support Library這個兼容庫設計地有些莫名其妙,它為了提供向后兼容的特性,替換了整個Fragment框架。比如,運行在3.1之后的系統系統上,使用的Fragment還是Support Library所提供的,而不是基於系統自身的(這一點在講到后面的時候非常重要)。

2、Fragment的嵌套

使用Fragment時最繁瑣復雜的就是多個Fragment之間的相互通信,必須通過Activity作為中間者傳遞。嵌套的Fragment一開始是不支持的,因為會導致了各式各樣的bug。直到API 17,也就是Jelly Bean 4.2,終於開始支持嵌套的Fragments,並且這個功能也被添加到了Support Library里面。使用Fragment來搭建頁面的夢想實現的一天終於到來了,這種方式有一個巨大的好處,就是解放Activity,使用多個Fragment組件來承載UI和邏輯。

夢想很美好,現實很殘酷!

3、Fragment嵌套BUG之一:突變的動畫效果

問題: 交互體驗做到極致的APP,都會使UI具有平滑順暢的動畫效果。FragmentManager是允許通過設置轉場過渡動畫的。但是,退出動畫會導致嵌套的Fragment在動畫剛剛開始時就瞬間消失。

原因: Fragments有一個嵌套的生命周期,導致嵌套的Fragment會在其宿主Fragment前執行相應的生命周期,比如onStop。由於宿主Fragment的FragmentManager無法識別嵌套的Fragment,在動畫開始執行的時候,嵌套的Fragment的視圖樹會直接跳過動畫階段,但是宿主Fragment的動畫卻還在執行。所以宿主Fragment和嵌套Fragment動畫的步調是完全不一致的。

解決: 參考Stack Overflow上的一個解決方案:http://stackoverflow.com/questions/14900738/nested-fragments-disappear-during-transition-animation 原理是緩存宿主Fragment的當前可見狀態,但是這個會導致頁面重繪,可能衍生出其它的問題。

4、Fragment嵌套BUG之一:被繼承的setRetainInstance

Fragments可以設置成保持狀態。比如,當屏幕旋轉導致Activity銷毀和重啟時,可以不用重新創建Fragment。

問題: 嵌套的Fragment會繼承宿主Fragment的retain instance狀態。

原因: 不明

解決: 尚無解決方案。

這個看起來是個很小的點,但是卻可能產生很大的問題。雖然個人傾向於讓所有fragments重新創建來保證其狀態不出錯(尤其是有復雜View的場景下),但是如果遇到不存在或簡單View的場景是,比如網絡請求或者多個組件調用,可能會設置一個回調監聽器,而這個監聽器是不需要重復創建的。上面所說的這種Fragment如果被嵌套在一個需要重新創建的Fragment里面,由於setRetainInstance 的繼承性,會導致這個Fragment也跟着被重新創建。我的解決方式是使用靜態實例和弱引用來持有這個Fragment,保證其不需要重新創建,有點坑。。。

5、Fragment嵌套BUG之一:錯亂的onActivityResult傳遞

這是最讓人頭疼的問題了,而且我們會經常遇到,比如在嵌套的Fragment里面啟動Activity。

問題: onActivityResult回調不會走到嵌套的Fragment里面。

原因: Support Library(V4)會修改了requestCode,使其中包含了一個Fragment 16位的索引值。這個索引值是與FragmentManager相關聯的,Activity會根據這個索引值在自身的FragmentManager里面搜索Fragment來分發onActivityResult,但是只能搜尋到宿主Fragment,而宿主Fragment卻不會向其內部嵌套的Fragment分發。這樣就導致嵌套的Fragment永遠收不到onActivityResult回調。

解決: 宿主Fragment向其內部嵌套的Fragment發送onActivityResult回調。

補充: 使用系統自帶的Fragment不會出現這種問題,谷歌還是很牛逼的哈!


測試源碼倉庫:https://github.com/BurntBrunch/android-fragment-bugs

結束,謝謝觀賞!


免責聲明!

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



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