美文网首页
FragmentPagerAdapter动态移除问题解决

FragmentPagerAdapter动态移除问题解决

作者: 坑逼的严 | 来源:发表于2019-08-28 11:37 被阅读0次

    在做一个项目的时候,遇到了FragmentPagerAdapter 要动态移除和添加fragment的问题,开始时我用的是如下代码:

    public class NewsPagerAdapter extends FragmentPagerAdapter  {
        private List<NewsFragment> fragments;
        public NewsPagerAdapter(FragmentManager fm, List<NewsFragment> fragments) {
            super(fm);
            this.fragments = fragments;
        }
    
        @Override
        public Fragment getItem(int i) {
            return fragments.get(i);
        }
    
        @Override
        public int getCount() {
            return fragments.size();
        }
    
        public void updateList(List<NewsFragment> fragments) {
            this.fragments = fragments;
            notifyDataSetChanged();
        }
        
    }
    

    然后调用UpdateList发现并没有更新,原本的页面还在,查了资料说FragmentStatePagerAdapter 可以完美解决

    public class NewsPagerAdapter extends FragmentStatePagerAdapter {
        private List<NewsFragment> fragments;
        public NewsPagerAdapter(FragmentManager fm, List<NewsFragment> fragments) {
            super(fm);
            this.fragments = fragments;
        }
    
        @Override
        public Fragment getItem(int i) {
            return fragments.get(i);
        }
    
        @Override
        public int getCount() {
            return fragments.size();
        }
    
        public void updateList(List<NewsFragment> fragments) {
            this.fragments = fragments;
            notifyDataSetChanged();
        }
        /**
         * 使用这个方式,让页面不缓存,能够在清除fragment的时候对其做了删除
         *
         * @param object
         * @return
         */
        @Override
        public int getItemPosition(Object object) {
            return PagerAdapter.POSITION_NONE;
        }
    }
    

    注意要重写getItemPosition方法
    跟踪原因,查看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);
        }
    

    原来不是remove而是detach,所以没办法真的移除

    而FragmentStatePagerAdapter内部销毁是采用remove

    @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            Fragment fragment = (Fragment) object;
            //它是采用的remove方式
            mCurTransaction.remove(fragment);
        }
    

    那么为什么还要重写getItemPosition方法?

    我们看源码

    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使用PagerAdapter.POSITION_NONE,在adapter调用notifyDataSetChange的时候,那么ViewPager的dataSetChanged()方法会被调用。

    最终效果


    1566983118457.gif

    相关文章

      网友评论

          本文标题:FragmentPagerAdapter动态移除问题解决

          本文链接:https://www.haomeiwen.com/subject/gtjpectx.html