天天看點

ViewPager頁面滑動Fragment銷毀問題

1、使用場景

ViewPager+Fragment實作界面切換,界面數量>=3

ViewPager頁面滑動Fragment銷毀問題

2、Fragment生命周期以及與Activity生命周期對比

ViewPager頁面滑動Fragment銷毀問題
ViewPager頁面滑動Fragment銷毀問題

3、問題描述

按上圖所說,隻有當Fragment所Attached的Activity執行destroy的時候才會調用onDestoryView方法,然而現實是: 當界面由2切換到1的時候,3界面對應的Fragment實際上走了如下流程:

1 -->onPause
    2 -->onStop
    3 -->onDestroyView      

再由1切換回2或者3時,3界面對應的Fragment的執行流程:

1 -->onCreateView
    2 -->onStart
    3 -->onResume      

可見,界面3對應的Fragment被銷毀并重新建立。

4、原因分析

ViewPager的預設加載方式是緩存目前界面前後相鄰的兩個界面,即最多共緩存包括目前界面在内的三個界面資訊。當滑動切換界面的時候,非相鄰界面資訊将被釋放。 界面2是目前界面,界面1和3是緩存界面,當切換到1時,界面2仍緩存,界面3被銷毀釋放,于是便有了onDestroyView的調用。 由1切換到2或3時,界面3又被重新建立,于是走了onCreateView流程。

5、解決方案

  • 方案一:設定ViewPager的緩存界面數

此方案适用于界面數較少的情況,避免緩存界面太多導緻記憶體吃緊。 方法:

mPager .setOffscreenPageLimit(2);      

參數:int limit    -    緩存目前界面每一側的界面數

以上述為例,目前界面為1,limit = 2,表示緩存2、3兩個界面。如此便避免了界面3被銷毀。 

  • 方案二:儲存狀态并恢複

此方案适用于可用界面資訊可由狀态儲存和恢複實作的情況。 在onDestroyView方法内儲存相關資訊,在onCreateView方法内恢複資訊設定。  

  • 方案三(推薦):複用Fragment的RootView

此方案适用通用場景,推薦使用。 步驟1:在onDestroyView方法内把Fragment的RootView從ViewPager中remove [html]  view plain  copy  

ViewPager頁面滑動Fragment銷毀問題
ViewPager頁面滑動Fragment銷毀問題
  1. @Override  
  2.     public void onDestroyView() {  
  3.         LogUtils.d(TAG , "-->onDestroyView");  
  4.         super .onDestroyView();  
  5.         if (null != FragmentView) {  
  6.             ((ViewGroup) mFragmentView.getParent()).removeView(mFragmentView);  
  7.         }  
  8.     }  

步驟2:在onCreateView方法内複用RootView [html]  view plain  copy  

ViewPager頁面滑動Fragment銷毀問題
ViewPager頁面滑動Fragment銷毀問題
  1. @Override  
  2.     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {  
  3.         if (null == mFragmentView) {  
  4.              mFragmentView = inflater.inflate(R.layout.fragment, container, false);  
  5.              mListView = (ListView) mFragmentView .findViewById(R.id.mm_listview);  
  6.              mListView.setAdapter(mAdapter);  
  7.        }  
  8.        return mFragmentView ;  
  9.    }