前面的那些个原理,身为安卓的开发者大家心里都很清楚,就不一一复述了。这里只说明一点,对于某一个页面是否需要重新关联数据的判定上,FragmentStatePagerAdapter 和 FragmentPagerAdapter 是一样的,通过getItemPosition来决定的:
/**
* 在此方法中找到需要更新的位置返回POSITION_NONE,否则返回POSITION_UNCHANGED即可
* @param object 其实就是fragment
*/
@Override
public int getItemPosition(@NonNull Object object) {
// POSITION_UNCHANGED = -1; 表示当前Fragment无需修改
// POSITION_NONE = -2; 表示当前Fragment需要更新
return -1;
}
那就比较简单了,可以想个办法让它判定出哪个位置应该POSITION_NONE,哪个位置应该为POSITION_UNCHANGED就行了,源代码如下:
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.util.SparseArray;
import java.util.List;
/**
* 加载显示Fragment的ViewPagerAdapter基类
* 提供可以刷新的方法
*/
public class BaseFragmentPagerAdapter extends FragmentStatePagerAdapter {
private List<Fragment> mFragmentList;
private FragmentManager mFragmentManager;
/**
* 下面两个值用来保存Fragment的位置信息,用以判断该位置是否需要更新
*/
private SparseArray<String> mFragmentPositionMap;
private SparseArray<String> mFragmentPositionMapAfterUpdate;
public BaseFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
mFragmentList = fragments;
mFragmentManager = fm;
mFragmentPositionMap = new SparseArray<>();
mFragmentPositionMapAfterUpdate = new SparseArray<>();
setFragmentPositionMap();
setFragmentPositionMapForUpdate();
}
/**
* 保存更新之前的位置信息,用<hashCode, position>的键值对结构来保存
*/
private void setFragmentPositionMap() {
mFragmentPositionMap.clear();
for (int i = 0; i < mFragmentList.size(); i++) {
mFragmentPositionMap.put(Long.valueOf(getItemId(i)).intValue(), String.valueOf(i));
}
}
/**
* 保存更新之后的位置信息,用<hashCode, position>的键值对结构来保存
*/
private void setFragmentPositionMapForUpdate() {
mFragmentPositionMapAfterUpdate.clear();
for (int i = 0; i < mFragmentList.size(); i++) {
mFragmentPositionMapAfterUpdate.put(Long.valueOf(getItemId(i)).intValue(), String.valueOf(i));
}
}
/**
* 在此方法中找到需要更新的位置返回POSITION_NONE,否则返回POSITION_UNCHANGED即可
* @param object 其实就是fragment
*/
@Override
public int getItemPosition(Object object) {
int hashCode = object.hashCode();
//查找object在更新后的列表中的位置
String position = mFragmentPositionMapAfterUpdate.get(hashCode);
//更新后的列表中不存在该object的位置了
if (position == null) {
return POSITION_NONE;
} else {
//如果更新后的列表中存在该object的位置, 查找该object之前的位置并判断位置是否发生了变化
int size = mFragmentPositionMap.size();
for (int i = 0; i < size; i++) {
int key = mFragmentPositionMap.keyAt(i);
if (key == hashCode) {
String index = mFragmentPositionMap.get(key);
if (position.equals(index)) {
//位置没变依然返回POSITION_UNCHANGED
return POSITION_UNCHANGED;
} else {
//位置变了
return POSITION_NONE;
}
}
}
}
return POSITION_UNCHANGED;
}
/**
* 将指定的Fragment替换/更新为新的Fragment
*
* @param oldFragment 旧Fragment
* @param newFragment 新Fragment
*/
public void replaceFragment(Fragment oldFragment, Fragment newFragment) {
int position = mFragmentList.indexOf(oldFragment);
if (position == -1) {
return;
}
//从Transaction移除旧的Fragment
removeFragmentInternal(oldFragment);
//替换List中对应的Fragment
mFragmentList.set(position, newFragment);
//刷新Adapter
notifyItemChanged();
}
/**
* 将指定位置的Fragment替换/更新为新的Fragment,同{@link #replaceFragment(Fragment oldFragment, Fragment newFragment)}
*
* @param position 旧Fragment的位置
* @param newFragment 新Fragment
*/
public void replaceFragment(int position, Fragment newFragment) {
Fragment oldFragment = mFragmentList.get(position);
removeFragmentInternal(oldFragment);
mFragmentList.set(position, newFragment);
notifyItemChanged();
}
/**
* 移除指定的Fragment
*
* @param fragment 目标Fragment
*/
public void removeFragment(Fragment fragment) {
//先从List中移除
mFragmentList.remove(fragment);
//然后从Transaction移除
removeFragmentInternal(fragment);
//最后刷新Adapter
notifyItemChanged();
}
/**
* 移除指定位置的Fragment,同 {@link #removeFragment(Fragment fragment)}
*
* @param position
*/
public void removeFragment(int position) {
Fragment fragment = mFragmentList.get(position);
//然后从List中移除
mFragmentList.remove(fragment);
//先从Transaction移除
removeFragmentInternal(fragment);
//最后刷新Adapter
notifyItemChanged();
}
/**
* 添加Fragment
*
* @param fragment 目标Fragment
*/
public void addFragment(Fragment fragment) {
mFragmentList.add(fragment);
notifyItemChanged();
}
/**
* 添加一组Fragment
* @param fragmentList 目标Fragment
*/
public void addFragmentList(List<Fragment> fragmentList) {
mFragmentList.addAll(fragmentList);
notifyItemChanged();
}
/**
* 在指定位置插入一个Fragment
*
* @param position 插入位置
* @param fragment 目标Fragment
*/
public void insertFragment(int position, Fragment fragment) {
mFragmentList.add(position, fragment);
notifyItemChanged();
}
private void notifyItemChanged() {
//刷新之前重新收集位置信息
setFragmentPositionMapForUpdate();
notifyDataSetChanged();
setFragmentPositionMap();
}
/**
* 从Transaction移除Fragment
*
* @param fragment 目标Fragment
*/
private void removeFragmentInternal(Fragment fragment) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.remove(fragment);
transaction.commitNow();
}
/**
* 此方法不用position做返回值即可破解fragment tag异常的错误
* 如果是 FragmentPagerAdapter,则需要添加上 @Override
*/
// @Override
public long getItemId(int position) {
// 获取当前数据的hashCode,其实这里不用hashCode用自定义的可以关联当前Item对象的唯一值也可以,只要不是直接返回position
return mFragmentList.get(position).hashCode();
}
@Override
public Fragment getItem(int position) {
return mFragmentList.get(position);
}
@Override
public int getCount() {
return mFragmentList.size();
}
public List<Fragment> getFragments() {
return mFragmentList;
}
/**
* 由于 fragment.setArguments(); 方法传递的参数会被 FragmentStatePagerAdapter 所缓存
* ,为了节省内存,重写这个方法返回空可以阻止FragmentStatePagerAdapter的缓存操作
* @return
*/
@Override
public Parcelable saveState() {
return null;
}
}
具体示例:https://github.com/jasonMouse/ViewPagerDemo
特别鸣谢10头条:http://www.10tiao.com/html/169/201805/2650825533/1.html
特别鸣谢川峰大神:https://blog.csdn.net/lyabc123456/article/details/79797552
网友评论