1. 程式人生 > >Android FragmentPagerAdapter資料重新整理notifyDataSetChanged沒效果研究或不執行OnCreatView方法導致介面不重新整理

Android FragmentPagerAdapter資料重新整理notifyDataSetChanged沒效果研究或不執行OnCreatView方法導致介面不重新整理

今天遇到一個問題是Fragment+ViewPager搭配使用的時候,頁面重新整理不執行OnCreateView方法到時,資料是有重新整理了,但是UI介面沒有重新整理,還是原來的資料顯示。
下面先說說我專案中的需求吧,這樣我們可以針對問題去解決。
需求:在一個頁面中使用ViewPager+Fragment搭配使用,在ViewPager中實現不同頁面的滑動。並且ViewPager中的頁面數量是根據網路請求回來的資料進行新增的。每個頁面還都有相應的網路請求。這裡還要考慮到的因素是如果網路請求出錯的時候,那麼沒有資料ViewPager就不能根據資料進行頁面的新增,這裡就要預設的顯示一個頁面。
我這裡的做法是:先定義一個容量來裝載頁面ArrayList fragments,程式一進入的時候先預設的給fragments新增一個頁面預設顯示,後面再在網路請求回資料的時候再fragments.clear();清空列表的資料,再重新新增頁面資料。運行了之後,根本就沒有效果。當你更新裡fragment List集合後呼叫FragmentPagerAdapter 的notifyDataSetChanged方法時發現數據根本就沒有重新整理。網路上會提到pageadapter的重新整理方案如下程式碼:
複寫pageradapter的getItemPosition方法設定tag為POSITION_NONE意思是沒有找到child要求重新載入。

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

結果你發現是重新整理了一下但內容還是原始的資料。通過對fragmentpageadapter的原始碼檢視你會在instantiateItem方法裡面發現這一段

 // Do we already have this fragment?
        String name = makeFragmentName(container.getId(), position);
        Fragment fragment =
mFragmentManager.findFragmentByTag(name); if (fragment != null) { if (DEBUG) Log.v(TAG, "Attaching item #" + position + ": f=" + fragment); mCurTransaction.attach(fragment); } else { fragment = getItem(position); if (DEBUG) Log.v(TAG, "Adding item #"
+ position + ": f=" + fragment); mCurTransaction.add(container.getId(), fragment, makeFragmentName(container.getId(), position)); }

原來他會先去FragmentManager裡面去查詢有沒有相關的fragment如果有就直接使用如果沒有才會觸發fragmentpageadapter的getItem方法獲取一個fragment。所以你更新的fragmentList集合是沒有作用的,還要清除FragmentManager裡面快取的fragment。解決辦法:在繼承的fragmentpageadapter類裡面新增這麼一個方法

public void setFragments(ArrayList<Fragment> fragments) {
        if(this.fragments != null){
            FragmentTransaction ft = fm.beginTransaction();
            for(Fragment f:this.fragments){
                ft.remove(f);
            }
            ft.commit();
            ft=null;
            fm.executePendingTransactions();
        }
        this.fragments = fragments;
        notifyDataSetChanged();
    }

完整程式碼如下:


    class MyFragmentPagerAdapter extends FragmentPagerAdapter {
        private ArrayList<Fragment> mFragments;
        private FragmentManager fm;
        public MyFragmentPagerAdapter(FragmentManager fm,ArrayList<Fragment> fragments) {
            super(fm);
            this.mFragments = fragments;
            this.fm = fm;
        }

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

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

        public void setFragments(ArrayList<Fragment> fragments) {
            if(this.mFragments != null){
                FragmentTransaction ft = fm.beginTransaction();
                for(Fragment f:this.mFragments){
                    ft.remove(f);
                }
                ft.commit();
                ft=null;
                fm.executePendingTransactions();
            }
            this.mFragments = fragments;
            notifyDataSetChanged();
        }

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

    }

可惜的是這樣資料是重新整理了,但是還是沒有效果,因為FragmentPagerAdapter只是在之前已經有了 的頁面重新整理了資料,但是沒有執行OnCreateView()方法,導致UI介面沒有重新整理,還是顯示原來的資料。
其實問題我們已經解決了一半了。通過搜尋資料:
對於OnCreateView沒有執行,網上有以下幾種說法:
1.將FragmentAdapter換成FragmentStatePagerAdapter。

2.設定ViewPager的setOffscreenPageLimit。

3.getItem(int id)在此方法中建立需要的Fragment。

這裡我就只用了第一種方法就成功了。只需要把FragmentPagerAdapter 替換為FragmentStatePagerAdapter就可以了。

 class MyFragmentPagerAdapter extends FragmentStatePagerAdapter {
        private ArrayList<Fragment> mFragments;
        private FragmentManager fm;
        public MyFragmentPagerAdapter(FragmentManager fm,ArrayList<Fragment> fragments) {
            super(fm);
            this.mFragments = fragments;
            this.fm = fm;
        }

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

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

        public void setFragments(ArrayList<Fragment> fragments) {
            if(this.mFragments != null){
                FragmentTransaction ft = fm.beginTransaction();
                for(Fragment f:this.mFragments){
                    ft.remove(f);
                }
                ft.commit();
                ft=null;
                fm.executePendingTransactions();
            }
            this.mFragments = fragments;
            notifyDataSetChanged();
        }

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

    }