天天看点

ViewPage中Fragment替换失败的解决方法

相信在android开发中,使用ViewPage是必须的,而和ViewPage配合使用的那就属Fragment最为常见了,还有就是ImageView。
今天所说的是Fragment在ViewPage中的使用,通常我们所使用的适配器是FragmentPagerAdapter。一般情况下,我们在ViewPage中添加的碎片(Fragment)是固定的,不会发生变更的,那么在FragmentPagerAdapter适配器中重写的几个方法就是固定的,不需要重写其他的方法,这里我就不再赘述了。
可是如果ViewPage中的碎片在某种情况下出现替换,该如何处理呐?
通常的思路就是: 使用 FragmentPagerAdapter 将所有的碎片添加到ViewPage中,如果在某个条件的触发下,更改Fragment的数据源,然后再通过notifyDataSetChanged()的方法,通知适配器更新数据,可是如果这样运行的话,发现其中该被替换掉的碎片没有被替换掉,还是会出现原先的碎片,不管你如何清理ViewPage中的控件、如何更改数据源,碎片始终还是不会被替换。
那我们就会想,代码没问题呀!逻辑没错呀!为什么就是不被替换呐????
我认为这个主要是缓存的问题,我们第一次添加到ViewPage中的碎片被放到了缓存中了,等我们需要替换其中某个碎片时,只是更改了数据源,而在缓存中的还是之前的碎片,所以不管你怎么切换都不会把碎片替换掉。
其实解决的方法有三种:
           

一、继续使用FragmentPagerAdapter ,重写 instantiateItem(ViewGroup container, int position) 方法。

贴上适配器中的代码如下:

public class MyAdapter extends FragmentPagerAdapter {

    protected List<Fragment> fragmentsList;  //数据源
    private boolean[] flags;  //标记碎片的

    private FragmentManager fm;

    public MyAdapter(FragmentManager fm, List<Fragment> fragments) {
        super(fm);
        this.fm = fm;
        this.fragmentsList = fragments;
        flags = new boolean[fragmentsList.size()];
    }

   //提供一个公共方法,供其他类调用,刷新适配器
    public void refresh(int... indexs) {
        for (int i = ; i < indexs.length; i++) {
            flags[indexs[i]] = true;
        }
        notifyDataSetChanged();
    }

   /**
   * POSITION_NONE;//返回这个表示该对象已改变,需要刷新
   * POSITION_UNCHANGED;//反之不刷新
   */
    @Override
    public int getItemPosition(Object object) {
        // TODO Auto-generated method stub
        return PagerAdapter.POSITION_NONE;
    }

   //这个方法是重点,只有重写了这个方法才会实现碎片的替换。
    @Override
    public Object instantiateItem(ViewGroup container, int position) {

        Fragment fragment = (Fragment) super.instantiateItem(container, position);
        // 得到Tag
        String fragmentTag = fragment.getTag();
        if (flags[position % flags.length] && fragment != fragmentsList.get(position % fragmentsList.size())) {
            // 如果这个Fragment需要更新
            FragmentTransaction ft = fm.beginTransaction();
            // 移除旧的Fragment
            ft.remove(fragment);
            // 换成新的Frgment
            fragment = fragmentsList.get(position % fragmentsList.size());
            // 用之前的Tab添加新的Frgament
            ft.add(container.getId(), fragment, fragmentTag);
            ft.attach(fragment);
            ft.commitAllowingStateLoss();
            // 复位更新标志
            flags[position % flags.length] = false;
        }
        return fragment;
    }

    @Override
    public int getCount() {
        return fragmentsList.size();
    }

    @Override
    public Fragment getItem(int arg0) {
        return fragmentsList.get(arg0);
    }

} 
           

二、使用FragmentStatePagerAdapter适配器,也许重写instantiateItem(ViewGroup container, int position) 。

代码如下:

public class ViewPageAdapter extends FragmentStatePagerAdapter {

        private List<Fragment> mDataList;

        public ViewPageAdapter(FragmentManager fm, List<Fragment> list) {
            super(fm);
            mDataList = list;
        }

        @Override
        public Fragment getItem(int position) {
            return mDataList.get(position);
        }

        @Override
        public int getItemPosition(Object object) {
            return PagerAdapter.POSITION_NONE;
        }

        @Override
        public int getCount() {
            return mDataList.size();
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            final Object fragment = super.instantiateItem(container, position);
            try {
                final Field saveFragmentStateField = Fragment.class.getDeclaredField("mSavedFragmentState");
                saveFragmentStateField.setAccessible(true);
                final Bundle savedFragmentState = (Bundle) saveFragmentStateField.get(fragment);
                if (savedFragmentState != null) {
                    savedFragmentState.setClassLoader(Fragment.class.getClassLoader());
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return fragment;
        }
    }
           

三、使用Fragment的管理器FragmentManager来对Fragment进行替换。

具体方法点击此链接

以上三种方法是我对Fragment的替换所采取的方法,如若有更好的方法或有不足之处,望指出!谢谢!