在做一个项目的时候,遇到了FragmentPagerAdapter 要动态移除和添加fragment的问题,开始时我用的是如下代码:
public class NewsPagerAdapter extends FragmentPagerAdapter {
private List<NewsFragment> fragments;
public NewsPagerAdapter(FragmentManager fm, List<NewsFragment> fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int i) {
return fragments.get(i);
}
@Override
public int getCount() {
return fragments.size();
}
public void updateList(List<NewsFragment> fragments) {
this.fragments = fragments;
notifyDataSetChanged();
}
}
然后调用UpdateList发现并没有更新,原本的页面还在,查了资料说FragmentStatePagerAdapter 可以完美解决
public class NewsPagerAdapter extends FragmentStatePagerAdapter {
private List<NewsFragment> fragments;
public NewsPagerAdapter(FragmentManager fm, List<NewsFragment> fragments) {
super(fm);
this.fragments = fragments;
}
@Override
public Fragment getItem(int i) {
return fragments.get(i);
}
@Override
public int getCount() {
return fragments.size();
}
public void updateList(List<NewsFragment> fragments) {
this.fragments = fragments;
notifyDataSetChanged();
}
/**
* 使用这个方式,让页面不缓存,能够在清除fragment的时候对其做了删除
*
* @param object
* @return
*/
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
}
注意要重写getItemPosition方法
跟踪原因,查看FragmentPagerAdapter内部的添加和移除方法:
@Override
public Object instantiateItem(ViewGroup container, int position) {
//这里获取的itemId,就是position
final long itemId = getItemId(position);
// Do we already have this fragment?
//获取的tag,就是容器id和position,问题就在这里
String name = makeFragmentName(container.getId(), itemId);
//利用Tag获取Fragment,那么获取出来当然还是最开始添加的一个,获取出来不为null,就不是使用新的列表中创建的了
Fragment fragment = mFragmentManager.findFragmentByTag(name);
if (fragment != null) {
if (DEBUG) Log.v(TAG, "Attaching item #" + itemId + ": f=" + fragment);
mCurTransaction.attach(fragment);
} else {
fragment = getItem(position);
if (DEBUG) Log.v(TAG, "Adding item #" + itemId + ": f=" + fragment);
mCurTransaction.add(container.getId(), fragment,
makeFragmentName(container.getId(), itemId));
}
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
//移除的时候竟然不是remove,是detach,看来它是为了还可以继续用
mCurTransaction.detach((Fragment)object);
}
原来不是remove而是detach,所以没办法真的移除
而FragmentStatePagerAdapter内部销毁是采用remove
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
Fragment fragment = (Fragment) object;
//它是采用的remove方式
mCurTransaction.remove(fragment);
}
那么为什么还要重写getItemPosition方法?
我们看源码
void dataSetChanged() {
// This method only gets called if our observer is attached, so mAdapter is non-null.
final int adapterCount = mAdapter.getCount();
mExpectedAdapterCount = adapterCount;
boolean needPopulate = mItems.size() < mOffscreenPageLimit * 2 + 1
&& mItems.size() < adapterCount;
int newCurrItem = mCurItem;
boolean isUpdating = false;
for (int i = 0; i < mItems.size(); i++) {
final ItemInfo ii = mItems.get(i);
final int newPos = mAdapter.getItemPosition(ii.object);
//默认的值,即不改变
if (newPos == PagerAdapter.POSITION_UNCHANGED) {
continue;
}
//如果设置这个的话,会移除item+调用destroyItem
if (newPos == PagerAdapter.POSITION_NONE) {
mItems.remove(i);
i--;
if (!isUpdating) {
mAdapter.startUpdate(this);
isUpdating = true;
}
//调用destroyItem,就可以remove掉了
mAdapter.destroyItem(this, ii.position, ii.object);
needPopulate = true;
if (mCurItem == ii.position) {
// Keep the current item in the valid range
newCurrItem = Math.max(0, Math.min(mCurItem, adapterCount - 1));
needPopulate = true;
}
continue;
}
if (ii.position != newPos) {
if (ii.position == mCurItem) {
// Our current item changed position. Follow it.
newCurrItem = newPos;
}
ii.position = newPos;
needPopulate = true;
}
}
}
getItemPosition使用PagerAdapter.POSITION_NONE,在adapter调用notifyDataSetChange的时候,那么ViewPager的dataSetChanged()方法会被调用。
最终效果
1566983118457.gif
网友评论