zoukankan      html  css  js  c++  java
  • viewPager+fragment如何刷新缓存fragment

    最近在做一个项目,有一个功能是答题翻页。于是需要实现在这一页的时候就缓存下一页。

    刚刚开始我是用

    setOnPageChangeListener方法监听,滑到这一页的时候才刷新这一页:
     public void onPageSelected(int position)
    {
       ReadFragment fragment= (ReadFragment) fragmentArrayList.get(position);
       fragment.refresh();
    }


    不过这样就只有滑动到这一页的时候才能用fragmentArrayList.get(position)获取当前页,用这种方法获取下一页的fragment就会报空指针。也就是说无法先缓存刷新下一页的内容。

    到底怎么样才能获取得到下一页的fragment呢?

    百度了一下好像说要在

    FragmentPagerAdapter里面的instantiateItem()处理。于是我看了一下它的源代码:
    @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;
        }

    可以看出:

    instantiateItem方法中并不是直接去List里面拿到Fragment,而是先从FragmentManager中通过Tag找对应的Fragment,如果可以找到就不会去List里面拿了,介于这种情况,我在adapter中加入了这个方法:

     public ReadFragment getFragment(int position)
        {
            String tag = getFragmentTag(mContainer.getId(),position);
            ReadFragment fragment = (ReadFragment) fm.findFragmentByTag(tag);
            return fragment;
    
        }
    
        /**
         * 运用反射机制调用FragmentPagerAdapter的getFragmentTag的方法
         * @param viewId
         * @param index
         * @return
         */
        private String getFragmentTag(int viewId, int index)
        {
            try {
                Class<FragmentPagerAdapter> cls = FragmentPagerAdapter.class;
                Class<?>[] parameterTypes = { int.class, long.class };
                Method method = cls.getDeclaredMethod("makeFragmentName",
                        parameterTypes);
                method.setAccessible(true);
                String tag = (String) method.invoke(this, viewId, index);
                return tag;
            } catch (Exception e) {
                e.printStackTrace();
                return "";
            }
        }

    在onPageSelected里面调用getFragment(int position)方法获取下一页的内容,达到当选中这一页的时候就先缓存刷新下一页。

    getFragment(int position)方法其实就是拿到缓存的fragment(这里的缓存是指viewpager缓存的fragment),不过就得先保证该fragment已经先在viewpager中缓存了,虽然内容还没有刷新(每个fragment里面显示的内容都是一样的),这样就不会报空指针了。

    出现了一个问题,onPageSelected在viewPager展示第一页的时候是不会调用的,所以第一页的内容还是得另外刷新,无法在onPageSelected里面刷新

    建立一个方法initData(),在里面单独刷新第一页的fragment。

    由于viewPager展示第一页的时候不会调用onPageSelected,那也就导致了第一页和第二页的内容都无法先得到缓存(因为第二页是在第一页选中的时候就事先开始缓存的),所以第一页和第二页的内容都得在initData()里面单独刷新,其它的通过onPageSelected里面的方法来刷新。

    到了这里总结一下思路:

    刚刚进入界面的时候:刷新第一页,缓存第二页。

    翻页时候:从第一页翻到第二页,执行onPageSelected()

                  onPagerSelected里面调用方法getFragment(int position),获取到下一页即第三页的fragment,然后刷新缓存内容。

                  从第二页翻到第三页:执行onPageSelected()

                  onPagerSelected里面调用方法getFragment(int position),获取到下一页即第四页的fragment,然后刷新缓存内容。

    结果又出现了又一个问题:从第一页翻到第二页的时候,闪退了,报空指针。

    后来调试了一下发现getFragment方法得到的fragment为null,没道理,为啥,想到最后才发现原来是因为第三页的fragment在viewPager中没有缓存,而我们的getFragment(int position)是通过tag标记向缓存中拿的。

    怎么才能让第三个fragment在viewPager中实现得到缓存呢?

    默认的,viewpager在第一页的时候会缓存第二页,到了第二页的时候会缓存第一与第二页,实践证明,只有当第二页完全显示的时候,第三页才会得到缓存,而onPagerSelected在fragment滑到超过屏幕一半而且我们手指放开了才会调用,如果我们的手指没有放开是不会被调用的,当我们的手指放开,onPagerSelected被调用的时候,第三页还没有得到缓存。

    怎么办?我又想到了

    @Override public void onPageScrollStateChanged(int state) {}
    本认为可以在里面判断state==2,即滑动停止的时候,才缓存刷新这一页,最后才发现还是有一样的问题

    原来滑动停止指的是手指的滑动,即手指离开屏幕,而不是指改fragment的滑动,因此还是会出现上面的情况。

    怎么办,不用怕:还有一个方法:readViewPager.setOffscreenPageLimit(2);

    该方法可以给你答案。

    这个方法可以设置viewPager当前页两边的缓存数目,如readViewPager.setOffscreenPageLimit(2);当前页左右各缓存2个。

    viewPager默认的是readViewPager.setOffscreenPageLimit(1);

    这样就OK了?,高兴太早了。滑到第五页的时候出问题了,是空白的。改为readViewPager.setOffscreenPageLimit(3);也一样。

    (此时我总共只有4个fragment,我采用的是无限循环模式,实际的fragment有4个)而实际缓存的有5个fragment(当前页加左右两个),会不会是这里出问题。

    关于怎么样设置无限循环,可以参考我另外一篇博客:http://www.cnblogs.com/tangZH/p/6516566.html

    于是我把fragment改为5个,结果没问题了。

    但是往回翻页的时候出问题了,翻几页后又出现了空白页,于是我改为6个fragment,才完全没问题。

    晕。

    还有往回翻页也需要刷新上一页的内容。

  • 相关阅读:
    在TreeView控件节点中显示图片
    PAT 甲级 1146 Topological Order (25 分)
    PAT 甲级 1146 Topological Order (25 分)
    PAT 甲级 1145 Hashing
    PAT 甲级 1145 Hashing
    PAT 甲级 1144 The Missing Number (20 分)
    PAT 甲级 1144 The Missing Number (20 分)
    PAT 甲级 1151 LCA in a Binary Tree (30 分)
    PAT 甲级 1151 LCA in a Binary Tree (30 分)
    PAT 甲级 1149 Dangerous Goods Packaging
  • 原文地址:https://www.cnblogs.com/tangZH/p/6583190.html
Copyright © 2011-2022 走看看