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;
}
}