问题描述:
场景:几个相同的页面,要左右切换,比如:天气3的首页
ViewPager使用FragmentPagerAdapter,新添加进adapter中的数据没有问题,而删除数据减少数据之后,Fragment的数据内容没有对号入座,没有变化,而内容显示的是其他已经删除的Fragment的数据。
已经急不可耐的小伙伴可以翻到文末查看解决方法
为什么会导致这个原因呢,是因为之前的Fragmet是缓存在内存中的,翻看FragmentPagerAdapter源码可以看到
@OverridepublicObject instantiateItem(ViewGroup container, intposition) {
if(mCurTransaction== null) {
mCurTransaction= mFragmentManager.beginTransaction();}
final longitemId = getItemId(position);// Do we already have this fragment?String name = makeFragmentName(container.getId(),itemId);Fragment fragment = mFragmentManager.findFragmentByTag(name);if(fragment != null) {
if(DEBUG) Log.v(TAG,"Attaching item #"+ itemId + ": f="+ fragment);mCurTransaction.attach(fragment);} else{
fragment = getItem(position);if(DEBUG) Log.v(TAG,"Adding item #"+ itemId + ": f="+ fragment);mCurTransaction.add(container.getId(),fragment,makeFragmentName(container.getId(),itemId));}
if(fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);fragment.setUserVisibleHint(false);}
returnfragment;}
如果Fragment不存在,那么会调用getItem方法重新取得Fragment,并且添加进事务管理中,也就是缓存在内存中,等待Activity被销毁之后才释放,反之已经存在的Fragment将不在重新创建,所以有时getItem方法有时候没有回调的原因就是因为,已经取了缓存内的数据了。
诸位看到这里是不是感觉找到真正原因了,其实不然!
毫于疑问这段代码完全没有问题,那问题出在哪儿呢?
相信诸位已经注意到了makeFragmentName这个方法,每个新添加的Fragment都添加了一个Tag。
final longitemId = getItemId(position);// Do we already have this fragment?String name = makeFragmentName(container.getId(),itemId);Fragment fragment = mFragmentManager.findFragmentByTag(name);
正是通过这个Tag才能让做到让每个Fragment是唯一的。问题就出在Tag上!
相信有许多小伙伴都习惯这样写,把getItemId的返回值直接返回position:
@Overridepublic longgetItemId(intposition) {
returnposition;}
那么问题来了,position有没有可能重复呢,答案当然是肯定的。正是添加的Fragment以position的名义打上了Tag,下一次数据减少的时候,又通过相同的position拿到了相同的Fragment,这里就也就重复了。
有点乱,举个粟子:
看到这里答案已经明显了,因为传的ID不对,所以导致取小花的时候把小明遗留在内存的Fragment取出来了,而导致了Fragment取错的原因。
代码很简单:
1、重写getItemId方法(推荐)
@Overridepublic longgetItemId(intposition) {
return这里换成自己的唯一ID;}
2、暴力重写instantiateItem与destroyItem(不推荐)
@Overridepublic voiddestroyItem(ViewGroup container, intposition,Object object) {
container.removeView(((Fragment) object).getView());// 移出viewpager两边之外的page布局}
@OverridepublicObject instantiateItem(ViewGroup container, intposition) {
Fragment fragment = getItem(position);if(!fragment.isAdded()) { // 如果fragment还没有addedFragmentTransaction ft = mFragmentManager.beginTransaction();ft.add(fragment,fragment.getClass().getSimpleName());ft.commit();mFragmentManager.executePendingTransactions();//同步的方式添加Fragment}
if(fragment.getView().getParent() == null) {
container.addView(fragment.getView());// 为viewpager增加布局}
returnfragment;}
如果有说得不对的地方请诸位指出,共同学习!