在項目開發(fā)中我們經(jīng)常會碰到這樣的需求: 一個左右滑動切換的Viewpager
凭涂,每一頁存在一個列表被济。這時大家一般都會采用Viewpager
加Fragment
的方式去實現(xiàn)救赐,每個頁面復(fù)用Adapter
。當(dāng)我使用如下的代碼并且頁面多于2個的時候只磷,會出現(xiàn)白屏問題Adapter
設(shè)置或刷新不生效的問題:
public class MyFragment extends BaseFragment {......
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle state) {
return inflater.inflate(R.layout.fragment_red, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
mListView = (RecyclerView) view.findViewById(R.id.rv_data);
if(mAdapter ==null){
mAdapter =new MyRedBagAdapter(mData);
mListView.setAdapter(mAdapter);
}else {
mAdapter.notifyDataSetChanged();
}
}
FragmentPagerAdapter源碼分析:
@Override
public Object instantiateItem(ViewGroup container, int position) {
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
復(fù)用的時候直接執(zhí)行attach()方法
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position); //通過name作為tag標(biāo)記在事務(wù)中緩存了Fragment
mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), itemId));
}
······
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
······ 在viewpager銷毀頁面的時候執(zhí)行了detach方法经磅,回收了頁面
mCurTransaction.detach((Fragment)object);
}
- FragmentPageAdapter在
instantiateItem()
方法中獲取Fragment,如果是第一次加載調(diào)用FragmentTransaction.add(...)
, 執(zhí)行的Fragment與Activity的生命周期方法是:Fragment.onAttach()
→Activity.onAttachFragment(Fragment)
→Fragment.performCreate()
→Fragment.onCreate()
→Fragment.performCreateView()
→Fragment.onCreateView()
→Fragment.onViewCreated()
钮追。 - FragmentPageAdapter在
instantiateItem()
方法中復(fù)用復(fù)用Fragment時FragmentTransaction.attach()
執(zhí)行的fragment的生命周期方法是:onCreateView()
→onViewCreated()
预厌。 - FragmentPageAdapter在
destoryItem()
中detach掉了需要銷毀的fragment,此時fragment的生命周期為:performDestroyView()
→onDestroyView()
→Fragment.mContainer.removeView(Fragment.mView)
元媚。
代碼缺陷:
- 分析源碼可知
onViewCreated()
執(zhí)行的前提是Fragment.mView不為空轧叽,因此onViewCreated()
方法的view
參數(shù)一定是非空的苗沧。 - 復(fù)用時同樣會調(diào)用
onCreateView()
,inflate創(chuàng)建一個新的view,因此RecyclerView\ListView也是一個全新的對象了炭晒,而Adapter仍然對應(yīng)的是舊的RecyclerView\ListView待逞。Notify自然就不會生效了,導(dǎo)致展示區(qū)一片空白网严。
解決方法:
-
復(fù)用
Fragment#onCreateView(...)
的返回值mInflated
(推薦)private View mInflated; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle) { if(mInflated == null) mInflated = inflater.inflate(R.layout.fragment_red, container, false); //findView ........ return mInflated; }
- 或者在
onDestoryView
時強制釋放adapter
(不推薦)@Override public void onDestroyView() { super.onDestroyView(); mAdapter = null; }