美文网首页
Android FragmentPagerAdapter动态增加

Android FragmentPagerAdapter动态增加

作者: LeonXtp | 来源:发表于2017-11-25 14:07 被阅读867次

    问题记录


    背景

    使用TabLayout+ViewPager+FragmentPagerAdapter实现经典的多Tab底部展示的布局结构。

    需求

    动态增删换Fragment

    问题症状

    删除异常,增加失败,替换失败

    问题原因

    问题主要还是在于FragmentPagerAdapter的缓存机制:

    FragmentPagerAdapter会缓存所有的经过instantiate()之后的Fragment,保存在一个 ArrayList<Fragment>的数据结构中。在从缓存中取出来复用的时候,是根据Container的ID+ItemId共同判断的。这个containerId是哪个Container呢?就是ViewPager。所以,决定缓存取出策略的,基本就是itemId了。

    由此也可以复现问题场景:

    假设有4个Fragment,现在要将下表为1的那个Fragment删除。你直接从你的List<Fragment>中删除了它,然后当你点击第1个时,显示的却还是原来那个。
    类似的,增加/替换,也是同样的症状。

    解决办法

    很简单,就是给每个Fragment都固定一个ID,在FragmentPagerAdaptergetItemId()方法中根据各种不同的展现情景返回,而不是默认的只返回position
    在这里,最简单的方式就是返回你的List<Fragment>FragmenthashCode

    这样就解决了增删替换的问题,如果要调换位置,也是可以的。

    相关系统源码


    READ THE FUCKING SOURCE CODE
    FragmentPagerAdapter:

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            ......
            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) {
                ......
                mCurTransaction.attach(fragment);
            } else {
                fragment = getItem(position);
                ......
                mCurTransaction.add(container.getId(), fragment,
                        makeFragmentName(container.getId(), itemId));
            }
           ......
            return fragment;
        }
    
        public long getItemId(int position) {
            return position;
        }
    
        private static String makeFragmentName(int viewId, long id) {
            return "android:switcher:" + viewId + ":" + id;
        }
    

    FragmentManager:

        public abstract Fragment findFragmentByTag(String tag);
    
        @Override
        public Fragment findFragmentByTag(String tag) {
            if (mAdded != null && tag != null) {
                // First look through added fragments.
                for (int i=mAdded.size()-1; i>=0; i--) {
                    Fragment f = mAdded.get(i);
                    if (f != null && tag.equals(f.mTag)) {
                        return f;
                    }
                }
            }
            ......
            return null;
        }
    

    其中mAdded声明是这样的:

        ArrayList<Fragment> mAdded;
    

    好了,看了以上的源码足够解决问题了。

    一篇不错的周期介绍

    相关文章

      网友评论

          本文标题:Android FragmentPagerAdapter动态增加

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