很多新闻类的App会有增加删除频道功能,也就是在ViewPager中动态的增加删除Fragment。标准的代码为
public class NewsFragmentPagerAdapter extends FragmentPagerAdapter {
private List<String> mTitles;
private List<Fragment> mNewsFragmentList;
private FragmentManager fm;
public NewsFragmentPagerAdapter(FragmentManager fm, List<String> titles, List<Fragment> newsFragmentList) {
super(fm);
this.fm = fm;
mTitles = titles;
mNewsFragmentList = newsFragmentList;
}
@Override
public CharSequence getPageTitle(int position) {
return mTitles.get(position);
}
@Override
public Fragment getItem(int position) {
return mNewsFragmentList.get(position);
}
@Override
public int getCount() {
return mNewsFragmentList.size();
}
}
这时候增加添加删除fragment的代码
public void addFragment(Fragment fragment, String title){
mTitles.add(title);
this.mNewsFragmentList.add(fragment);
notifyDataSetChanged();
}
public void remove(String title){
int index = mTitles.indexOf(title);
mTitles.remove(index);
mNewsFragmentList.remove(index);
notifyDataSetChanged();
}
在直接调用addFragment可以成功的添加Fragment。但是调用remove方法并不能移除fragment。viewpager调用setAdapter时会首先执行instantiateItem(ViewGroup container, int position)寻找是否添加过,如果添加过会直接使用,没添加过会执行getItem(int position)。所以当我们仅仅移除列表中的Fragment没生效,因为在adapter已经记录了fragment。再看
instantiateItem(ViewGroup container, int position)方法
@Override
public Object instantiateItem(ViewGroup container, int position) {
if (mCurTransaction == null) {
mCurTransaction = mFragmentManager.beginTransaction();
}
// 根据id来匹配fragment
final long itemId = getItemId(position);
// Do we already have this fragment?
String name = makeFragmentName(container.getId(), itemId);
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));
}
if (fragment != mCurrentPrimaryItem) {
fragment.setMenuVisibility(false);
fragment.setUserVisibleHint(false);
}
return fragment;
}
所以我们重写getItemId(int position)方法,根据fragment的id来查找。
@Override
public long getItemId(int position) {
// 获取当前数据的hashCode
int hashCode = mNewsFragmentList.get(position).hashCode();
return hashCode;
}
完美解决问题。
其实是可以直接使用FragmentStatePagerAdapter直接可以达到目的,但是不妥善处理会造成内存泄漏