- 1、 bug現(xiàn)象:當(dāng)手機上的app運行的數(shù)量 超過手機清理的上限,即內(nèi)存不足時,應(yīng)用進入后臺再次打開時嵌套的Fragment頁面顯示空白; 問題分析:內(nèi)存不足時,宿主Activity會被異常關(guān)閉,當(dāng)再次打開時,Activity重新創(chuàng)建,但嵌套的Fragment填充發(fā)生了錯亂。
解決問題:復(fù)現(xiàn)bug,會發(fā)現(xiàn)除嵌套的Fragment外,其他的Fragment顯示和點擊事件均正常,也就是說問題可以鎖定在嵌套的Fragment的宿主Fragment。 問題范圍鎖定后,查閱資料,發(fā)現(xiàn)與FragmentManager(Fragment管理類)有關(guān)?;乜创a, 問題在對象FragmentTransaction,發(fā)現(xiàn)宿主Activity和宿主Fragment獲取對象FragmentTransaction的方式均為 getSupportFragmentManager().beginTransaction(),而宿主Fragment需要使用getChildFragmentManager().beginTransaction(), 替換代碼,重新運行,問題解決; 總結(jié):Activity中獲取對象FragmentTransaction,統(tǒng)一使用getSupportFragmentManager().beginTransaction(); Fragment中獲取對象FragmentTransaction,統(tǒng)一使用getChildFragmentManager().beginTransaction()。
補充(語言有些書面難懂,不求甚解者可忽略):關(guān)于getChildFragmentManager() 和 getSupportFragmentManager() getChildFragmentManager()是fragment中的方法, 返回的是管理當(dāng)前fragment內(nèi)部子fragments的manager. getSupportFragmentManager()在activity和fragment中都有. 在activity中, 方法用getSupportFragmentManager(), 返回的是管理activity中fragments的manager. 在fragment中, 還叫g(shù)etSupportFragmentManager(), 返回的是把自己加進來的那個manager. 也即, 如果fragment在activity中, fragment.getFragmentManager()得到的是activity中管理fragments的那個manager. 如果fragment是嵌套在另一個fragment中, fragment.getFragmentManager()得到的是它的parent的getChildFragmentManager(). 總結(jié)就是: getFragmentManager()是本級別管理者, getChildFragmentManager()是下一級別管理者. 這實際上是一個樹形管理結(jié)構(gòu).
- 2、 bug現(xiàn)象:當(dāng)手機上的app運行的數(shù)量 超過手機清理的上限,即內(nèi)存不足時,應(yīng)用進入后臺再次打開時點擊或者滑動Fragment應(yīng)用閃退。
問題分析:內(nèi)存不足時,宿主Activity會被異常關(guān)閉,當(dāng)再次打開時,Activity重新創(chuàng)建, 但與Viewpager結(jié)合使用的Fragment生命周期異常,viewpager的適配器繼承自FragmentPagerAdapter,頁面雖然被恢復(fù), 但Fragment內(nèi)的數(shù)據(jù)均被回收,所以Fragment會出現(xiàn)空指針。
解決問題:經(jīng)不斷探索目前有兩種解決方案。
第一種,在Fragment集合放入適配器之前, 利用getSupportFragmentManager().getFragments(),獲取到新的List<Fragment>, 然后遍歷并刪除這個集合內(nèi)的所有的Fragment對象, 刪除Fragment對象的代碼:
getSupportFragmentManager().beginTransaction().remove(saveFragmentList.get(i)).commit()。
List<Fragment> saveFragmentList = getSupportFragmentManager().getFragments();
for (int i = 0; i < saveFragmentList.size(); i++) {
getSupportFragmentManager().beginTransaction().remove(saveFragmentList.get(i)).commit();
}
list1Fragment = new List1Fragment();
list2Fragment = new List2Fragment();
list3Fragment = new List3Fragment();
list4Fragment = new List4Fragment();
fragmentList.clear();
fragmentList.add(list1Fragment);
fragmentList.add(list2Fragment);
fragmentList.add(list3Fragment);
fragmentList.add(list4Fragment);
第二種,解釋起來比較麻煩,代碼比較直觀,直接上代碼。
List<Fragment> saveFragmentList = getSupportFragmentManager().getFragments();
if (saveFragmentList != null && saveFragmentList.size() > 0) {
list1Fragment = (List1Fragment) saveFragmentList.get(0);
list2Fragment = (List2Fragment) saveFragmentList.get(1);
list3Fragment = (List3Fragment) saveFragmentList.get(2);
list4Fragment = (List4Fragment) saveFragmentList.get(3);
} else {
list1Fragment = new List1Fragment();
list2Fragment = new List2Fragment();
list3Fragment = new List3Fragment();
list4Fragment = new List4Fragment();
}
fragmentList.clear();
fragmentList.add(list1Fragment);
fragmentList.add(list2Fragment);
fragmentList.add(list3Fragment);
fragmentList.add(list4Fragment);
個人比較傾向于第二種。這兩種方法的區(qū)別是,第一種會重新繪制所有相關(guān)的Fragment, 而第二種會保存Activity異常銷毀前的Fragment的展示狀態(tài)。