天天看點

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的替換所采取的方法,如若有更好的方法或有不足之處,望指出!謝謝!