Fragment經典問題——記憶體銷燬導致fragment重疊
阿新 • • 發佈:2019-02-16
今天QA提了一個bug,說我們的程式首頁怎麼突然像一堆翔一樣……我剛要發作,看了看她的螢幕,真TM像一堆翔,所有頁面都重疊在了一起!WTF!
講真,做Android這麼久還是第一次遇到fragment重疊的問題,之前只看過一些資料,這次終於趕上活的了!
來分析下原因。我們首頁是一個FragmentActivity,裡面有四個Fragment,通過show和hide維護各個頁面。當記憶體不足時,我們的宿主FragmentActivity被銷燬,而所有的Fragment例項被快取下來,則再回來首頁時,快取的fragment又重新被加載出來,此時show和hide對這些快取下來的Fragment例項無效,於是便出現重疊。
所以這種場景需要我們自己維護savedInstanceState快取檢視,在onCreate的時候根據savedInstanceState是否為空來判斷,是走正常的onCreate流程,還是給快取的檢視繫結資料的流程。
程式碼例項
@Override
protected void onCreate(Bundle savedInstanceState) {
……
if (savedInstanceState != null) {
//不為空說明快取檢視中有fragment例項,通過tag取出來
FragmentManager fragmentManager= getFragmentManager();
fragment1 = (MyFragment1) fragmentManager.findFragmentByTag("MyFragment1" );
fragment2 = (MyFragment2) fragmentManager.findFragmentByTag("MyFragment2");
}else{
fragment1 = findOrCreateFragment("MyFragment1", MyFragment1.class);
fragment2 = findOrCreateFragment("MyFragment2", MyFragment2.class);
}
……//資料繫結
}
@Nullable
private <T extends Fragment> T findOrCreateFragment (String tag, Class<T> fragmentClass) {
Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
if (fragment == null) {
try {
fragment = fragmentClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
return null;
}
}
return (T) fragment;
}
/**
* 通過該方法切換Fragments
**/
private void switchToFragment(int position) {
mSelectPosition = position;
Fragment showFragment = mFragmentList.get(position);
if (showFragment != mLastFragment) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (mLastFragment != null) {
transaction.hide(mLastFragment);
}
if (!showFragment.isAdded()) {
transaction.add(R.id.main_container, showFragment, showFragment.getClass().getName()).commitAllowingStateLoss();// 隱藏當前的fragment,顯示選中的fragment
} else {
transaction.show(showFragment).commitAllowingStateLoss();// 隱藏當前的fragment,顯示選中的fragment
}
mLastFragment = showFragment;
}
測試技巧
如果想重現上述場景,可開啟開發者選項中的“不保留後臺活動”,保證每次切換頁面,都殺死上個頁面。