本文主要討論Activity重建的時候如何獲取Fragment的。即如下情況:
具體通過四種方法來獲取復用Fragment。
下面將對這四種情況分別加以分析說明。
首先來壹個總結,不建議使用該方法獲取Fragment。理由有如下三點:
getFragments方法獲取的是所有已經添加到FragmentManager中的Fragment。但是這個FragmentManager中保存的不只是我們定義的Fragment,還有可能會包含其他用途的Fragment。
Fragment不僅僅是界面的載體,同時它可以用來實現生命周期的監聽,因為它的生命周期和Activity是壹致的,當我們不好監聽Activity的生命周期的時候,就可以使用Fragment來輔助監聽。圖片加載庫Glide和Android Jet Pack中的ViewModel都使用了這種模式。
前段時間就遇到過這樣的bug
然後就出現了類型轉換異常,FragmentA不能被強制轉換成FragmentB。
當時我百思不得其解,為什麽會出現這個問題啊,我明明是按照Fragment添加到FragmentManager的順序去獲取Fragment的啊。
直到我將getFragments獲取到的Fragment列表打印出來才發現,其中的Fragment順序和我添加到FragmentManager中的順序是不壹致的。
也就是說因為getFragments中獲取到的Fragment包含了妳不想要的Fragment,而這些Fragment的初始化時機又是不可預料的,所以就不能通過Fragment列表準確定位妳需要的Fragment。
這個情況我沒有遇到過,參考文章的作者 怪盜kidou 遇到過,就順便寫上了。
在版本25中Activity是新建的請款下,getFragments返回的是null,然後到了26版本,getFragments返回的就是Collectiions.EmpytList()。。。
這就導致原來基於null判斷的程序出現bug。
這個方法是通過Fragment中所在的ViewGroup的Android:id定義的id來查找,適合壹個ViewGroup中只存在壹個Fragment的情況。
當然,如果壹個ViewGroup中有多個Fragment的情況下也是可以使用的,不過這個時候獲取的就是最後添加到ViewGroup中的Fragment了。
該方法就是用來處理findFragmentById不適用的情況的。因為是通過Tag來查找Fragment,所以ViewGroup的id也就沒用了。
需要註意的地方:
有壹種情況下是不能夠使用getFragmentById和getFragmentByTag,那就是使用ViewPager管理Fragment的情況。
這種方法是可用的,但是太過麻煩,可以使用fm.putFragment和fm.getFragment來處理這種情況。
這兩個方法的使用如下:
可能有朋友會感覺這個和getFragmentByTag那麽像呢,好像沒什麽區別。
重點來了,因為在ViewPager中添加和移除Fragment是由ViewPager控制的,所以像是
這種方法就不能被使用了,既然無法在添加fragment的時候設置tag,那我們就不能夠通過tag直接從FragmentManager中的Fragment列表中獲取了。
那putFragment和getFragment方法是怎麽做到這壹點的呢?
我們查看下這兩個方法的源碼:
通過上述源碼,我們可以看出,putFragment將待存儲的Fragment的Tag和mIndex作為壹組數據存儲在bundle中,然後在getFragment方法內先從bundle中取出對應Tag的mIndex,最後根據這個mIndex從mActive中取出對應的Fragment。
mActive是真正存儲Fragment的對象,但是我們不能夠直接使用Tag從中取出,因為ViewPager是使用mIndex來作為key值存儲Fragment的。所以我們只能夠退而求其次,將Tag和mIndex聯系起來,達到間接使用Tag取出Fragment的效果。
下面是對上述源碼及步驟的圖形化表示:
註意事項:
參考: 妳真的會用Fragment嗎?Fragment復用的那些事兒