ViewPager使用FragmentPagerAdapter 踩坑-不能动态删除Fragment

很多时候我们使用ViewPager来包含Fragment的时候,都是使用FragmentPagerAdapter,大致如下,确实用起来采用官方封装好的PagerAdapter也很简单方便


public class TabFragmentPagerAdapter extends FragmentPagerAdapter {

    private List<Fragment> mFragmentList;

    public TabFragmentPagerAdapter(FragmentManager fm, List<Fragment> list) {
        super(fm);
        this.mFragmentList = list;
    }

    @Override
    public Fragment getItem(int position) {
        if (mFragmentList != null && position < mFragmentList.size()) {
            return mFragmentList.get(position);
        }
        return null;
    }

    @Override
    public int getCount() {
        if (mFragmentList == null) {
            return 0;
        }
        return mFragmentList.size();
    }
}

遇到的问题:实际使用的时候,如果我的Fragment需要动态添加和动态删除,就出现问题了,比如index为1的Fragment页面,在第二次刷新的时候,我将其移除,然后重新创建了一个来添加,最后效果就是,显示的依旧是第一次添加的index为1的页面,what?我明明移除了,更新为新的了呀!

跟踪原因,查看FragmentPagerAdapter内部的添加和移除方法:

@Override
    public Object instantiateItem(ViewGroup container, int position) {
        //这里获取的itemId,就是position
        final long itemId = getItemId(position);

        // Do we already have this fragment?
        //获取的tag,就是容器id和position,问题就在这里
        String name = makeFragmentName(container.getId(), itemId);
        //利用Tag获取Fragment,那么获取出来当然还是最开始添加的一个,获取出来不为null,就不是使用新的列表中创建的了
        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));
        }

        return fragment;
    }

    @Override
    public void destroyItem(ViewGroup container, int position, Object object) {
                //移除的时候竟然不是remove,是detach,看来它是为了还可以继续用
        mCurTransaction.detach((Fragment)object);
    }

大致看到了,这个FragmentPagerAdapter内部,就是采用detach方式来移除,导致新的没法添加,看来这种方式适合于Fragment固定,不动态删除修改的方式。

解决办法:采用FragmentStatePagerAdapter并重写getItemPosition

public class MyFragmentAdapter extends FragmentStatePagerAdapter {
    private List<Fragment> fragmentInfos;

    public MyFragmentAdapter(FragmentManager fm, List<Fragment> fragmentInfos) {
        super(fm);
        this.fragmentInfos = fragmentInfos;
    }

    public Fragment getItem(int position) {
        return fragmentInfos.get(position);
    }

    @Override
    public int getCount() {
        return fragmentInfos == null ? 0 : fragmentInfos.size();
    }

    /**
     * 使用这个方式,让页面不缓存,能够在清除fragment的时候对其做了删除
     *
     * @param object
     * @return
     */
    @Override
    public int getItemPosition(Object object) {
        return PagerAdapter.POSITION_NONE;
    }
}
  1. 查看FragmentStatePagerAdapter内部销毁的方法:
@Override
    public void destroyItem(ViewGroup container, int position, Object object) {
        Fragment fragment = (Fragment) object;
        //它是采用的remove方式
        mCurTransaction.remove(fragment);
    }
  1. getItemPosition使用PagerAdapter.POSITION_NONE,在adapter调用notifyDataSetChange的时候,那么ViewPager的dataSetChanged()方法会被调用,查看下去:
void dataSetChanged() {
        // This method only gets called if our observer is attached, so mAdapter is non-null.

        final int adapterCount = mAdapter.getCount();
        mExpectedAdapterCount = adapterCount;
        boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1
                && mItems.size() < adapterCount;
        int newCurrItem = mCurItem;

        boolean isUpdating = false;
        for (int i = 0; i < mItems.size(); i++) {
            final ItemInfo ii = mItems.get(i);
            final int newPos = mAdapter.getItemPosition(ii.object);
            //默认的值,即不改变
            if (newPos == PagerAdapter.POSITION_UNCHANGED) {
                continue;
            }

            //如果设置这个的话,会移除item+调用destroyItem
            if (newPos == PagerAdapter.POSITION_NONE) {
                mItems.remove(i);
                i--;

                if (!isUpdating) {
                    mAdapter.startUpdate(this);
                    isUpdating = true;
                }
                //调用destroyItem,就可以remove掉了
                mAdapter.destroyItem(this, ii.position, ii.object);
                needPopulate = true;

                if (mCurItem == ii.position) {
                    // Keep the current item in the valid range
                    newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));
                    needPopulate = true;
                }
                continue;
            }

            if (ii.position != newPos) {
                if (ii.position == mCurItem) {
                    // Our current item changed position. Follow it.
                    newCurrItem = newPos;
                }

                ii.position = newPos;
                needPopulate = true;
            }
        }
    }

到这里,大概就知道为什么会重写getItemPosition了。

ok,采用这个方式能解决了这个动态删除修改的问题了,希望能帮到大家。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值