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