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