Android ViewPager的FragmentPagerAdapter中Fragment不重新加载数据,并且使用的是其他缓存的Framgnet的问题

问题描述:

场景:几个相同的页面,要左右切换,比如:天气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;
}

如果有说得不对的地方请诸位指出,共同学习!



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值