1、使用場景
ViewPager+Fragment實作界面切換,界面數量>=3
2、Fragment生命周期以及與Activity生命周期對比
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
- @Override
- public void onDestroyView() {
- LogUtils.d(TAG , "-->onDestroyView");
- super .onDestroyView();
- if (null != FragmentView) {
- ((ViewGroup) mFragmentView.getParent()).removeView(mFragmentView);
- }
- }
步驟2:在onCreateView方法内複用RootView [html] view plain copy
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
- if (null == mFragmentView) {
- mFragmentView = inflater.inflate(R.layout.fragment, container, false);
- mListView = (ListView) mFragmentView .findViewById(R.id.mm_listview);
- mListView.setAdapter(mAdapter);
- }
- return mFragmentView ;
- }