很多app的主界面都是底部几个按钮,然后点击切换显示不同的UI展现,这种可以使用Viewpager+fragment的方式实现,但是一不注意就会有问题,
比如是使用FragmentPagerAdapter的话,如果viewpager设置了setCurrentItem(index);会先把index-1,index+1以及index中对应的Fragment中的view加载出来,如果index=0的话,就只加载2个fragment中的view了.当viewpager滑动到那个界面就会加载那个fragment的view,比如你从第一个滑动到第四个,然后又从第四个滑动到第一个,这个时候第四个view就会被回收,view就为null,意味着你来回切换,fragment中的view会重复的,因为之前Fragment中的onDestroyView()生命周期方法会执行,导致view就会被回收了,如果你再viewpager的滑动监听通过view做什么业务很容易导致NullPointerException异常,我之前项目就有遇到过,重复加载view的问题怎么解决呢?
第一:设置viewpager的缓存为你fragment的个数.
viewpager.setOffscreenPageLimit(fragment的个数);
这些现象,你可以通过打log自己去分析,
如果使用的是FragmentStatePagerAdapater,viewpager滑动的时候会把fragment从内存中清除,这个可以从源代码上去分析:
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Removing item #" + position + ": f=" + object
+ " v=" + ((Fragment)object).getView());
while (mSavedState.size() <= position) {
mSavedState.add(null);
}
mSavedState.set(position, fragment.isAdded()
? mFragmentManager.saveFragmentInstanceState(fragment) : null);
mFragments.set(position, null);
mCurTransaction.remove(fragment);
}
最后一行就是移除了Fragment,而FragmentPagerAdapter的源代码:
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
if (DEBUG) Log.v(TAG, "Detaching item #" + getItemId(position) + ": f=" + object
+ " v=" + ((Fragment)object).getView());
mCurTransaction.detach((Fragment)object);
}
最后一行就是把Fragment中View移除了,这就是二者很大的区别,所以说当Fragment比较多的时候就用FragmentStatePagerAdapter,因为它会之前的Fragment从内存中移除,这样就节省了内存,如果Fragment不多的情况下就使用FragmentPagerAdapter,
还有一个问题就是动态的加载Fragment,就是viewpager增加或者删除Fragment,这个在我项目中也遇到了,如果是FragmentStatePagerAdapter的话就要重写
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
如果是FragmentPagerAdapter的话就要重写:
@Override
public long getItemId(int position) {
int hashCode = mFragment.get(position).hashCode();
return hashCode;
}
然后记得把viewpager指向显示那一个fragment,比如viewpager.setCurrentItem(0);如果不调用这个,会发现他还是会显示当前删除的fragment,只有滑动后,那个fragment才会消失.