ViewPager使用FragmentPagerAdapter加載多個fragment,實現對已加載的list做插入、刪除及排序操作。
例子1:
List<Fragment> list = new ArrayList<>();
list.add(fragment1);
list.add(fragment2);
list.add(fragment3);
adapter = new MyListAdapter(list,fragmentManager);
viewpager.setAdapter(adapter);
//刪除fragment2
list.remove(fragment2);
adapter.notifyDataSetChanged();
執行上面代碼是沒任何改變的,因爲在調用adapter.notifyDataSetChanged()時adapter會通過getItemPosition(Object object)
來判斷是否刪除fragment:
通過重寫getItemPosition:
@Override
public int getItemPosition(Object object) {
//每次都刷新都調用instantiateItem 和destroyItem方法
return POSITION_NONE;
}
再次執行例子1,viewpager是有改變的但是不是期望的效果,繼續看源碼:
而getItemId(position)方法默認返回的是
到這裏可以發現instantiateItem()新增fragment是通過position創建一個name然後在
fragmentManager中查詢是否存在改name的fragment,存在就調用attch方法重新加載(這
裏與destroyItem方法的detach對於的,attch會重新創建View)。
所以例子1刪除fragment2時,list的size爲2,調用notifyDataSetChanged,
adapter會刪除所有的fragemnt調用instantiateItem重新添加,在創健fragment的name時
默認返回position,所以剩下兩個的name是以position爲0、1的tag,viewpager顯示的
是fragment1、fragment2,而不是fragment1、fragment3。
接下來MyFragmentPagerAdapter:
public abstract class MyFragmentPagerAdapter extends PagerAdapter{
private final FragmentManager mFragmentManager;
private FragmentTransaction mCurTransaction = null;
private Fragment mCurrentPrimaryItem = null;
public MyFragmentPagerAdapter(FragmentManager mFragmentManager){
this.mFragmentManager =mFragmentManager;
}
public abstract Fragment getItem(int position);
/**作爲fragment的標識,每個fragment都有單獨的標識,不能直接用position,否則在排序和刪除會出現fragment錯亂*/
public abstract long getItemId(int position);
@Override
public void startUpdate(ViewGroup container) {
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
final long itemId = getItemId(position);
String name = makeFragmentName(container.getId(), itemId);
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
/** mCurTransaction.attach(fragment);
* 用show、hide代替attach、detach,這樣fragment不會reCreateView
*/
mCurTransaction.show(fragment);
} else {
fragment = getItem(position);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
/** mCurTransaction.detach((Fragment)object);*/
mCurTransaction.hide((Fragment)object);
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment)object;
if (fragment != mCurrentPrimaryItem) {
if (mCurrentPrimaryItem != null) {
mCurrentPrimaryItem.setMenuVisibility(false);
mCurrentPrimaryItem.setUserVisibleHint(false);
}
if (fragment != null) {
fragment.setMenuVisibility(true);
fragment.setUserVisibleHint(true);
}
mCurrentPrimaryItem = fragment;
}
}
@Override
public int getItemPosition(Object object) {
//每次都刷新都調用instantiateItem 和destroyItem方法
return POSITION_NONE;
}
@Override
public void finishUpdate(ViewGroup container) {
if (mCurTransaction != null) {
mCurTransaction.commitAllowingStateLoss();
mCurTransaction = null;
mFragmentManager.executePendingTransactions();
}
}
@Override
public boolean isViewFromObject(View view, Object object) {
return ((Fragment)object).getView() == view;
}
@Override
public Parcelable saveState() {
return null;
}
@Override
public void restoreState(Parcelable state, ClassLoader loader) {
}
private static String makeFragmentName(int viewId, long id) {
return "android:switcher:" + viewId + ":" + id;
}
}
用法和FragmentPagerAdapter一樣,將getItemId改爲抽象方法,返回每個fragment的標識。