按照通常使用ListView的习惯做法,如果你只是更新保存Fragment的List数据,然后调用adapter的notifyDataSetChanged()是不会起作用的.

搜索了下发现此问题普遍存在,多数是说先移除Fragment再notifyDataSetChanged(),因为FragmentPagerAdapter内部会缓存Fragment,但是经测试发现仅仅这样干是不行的。

这可能是Android一个BUG, 与此问题相关的主要有两个方法:

  • getItemPosition()
  • instantiateItem()

具体的分析内容参见原文,那么重写后的adapter如下:

 /**
* 加载显示Fragment的ViewPagerAdapter基类
* 提供可以刷新的方法
*
* @author Fly
* @e-mail 1285760616@qq.com
* @time 2018/3/22
*/
public class BaseFragmentPagerAdapter extends FragmentPagerAdapter {
private List<BaseFragment> mFragmentList;
private FragmentManager mFragmentManager;
/**下面两个值用来保存Fragment的位置信息,用以判断该位置是否需要更新*/
private SparseArray<String> mFragmentPositionMap;
private SparseArray<String> mFragmentPositionMapAfterUpdate; public BaseFragmentPagerAdapter(FragmentManager fm, List<BaseFragment> fragments) {
super(fm);
mFragmentList = fragments;
mFragmentManager = fm;
mFragmentList = fragments;
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即可
*/
@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(BaseFragment oldFragment, BaseFragment 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(BaseFragment oldFragment, BaseFragment newFragment)}
* @param position 旧Fragment的位置
* @param newFragment 新Fragment
*/
public void replaceFragment(int position, BaseFragment newFragment) {
BaseFragment oldFragment = mFragmentList.get(position);
removeFragmentInternal(oldFragment);
mFragmentList.set(position, newFragment);
notifyItemChanged();
} /**
* 移除指定的Fragment
* @param fragment 目标Fragment
*/
public void removeFragment(BaseFragment fragment) {
//先从List中移除
mFragmentList.remove(fragment);
//然后从Transaction移除
removeFragmentInternal(fragment);
//最后刷新Adapter
notifyItemChanged();
} /**
* 移除指定位置的Fragment,同 {@link #removeFragment(BaseFragment fragment)}
* @param position
*/
public void removeFragment(int position) {
BaseFragment fragment = mFragmentList.get(position);
//然后从List中移除
mFragmentList.remove(fragment);
//先从Transaction移除
removeFragmentInternal(fragment);
//最后刷新Adapter
notifyItemChanged();
} /**
* 添加Fragment
* @param fragment 目标Fragment
*/
public void addFragment(BaseFragment fragment) {
mFragmentList.add(fragment);
notifyItemChanged();
} /**
* 在指定位置插入一个Fragment
* @param position 插入位置
* @param fragment 目标Fragment
*/
public void insertFragment(int position, BaseFragment fragment) {
mFragmentList.add(position, fragment);
notifyItemChanged();
} private void notifyItemChanged() {
//刷新之前重新收集位置信息
setFragmentPositionMapForUpdate();
notifyDataSetChanged();
setFragmentPositionMap();
} /**
* 从Transaction移除Fragment
* @param fragment 目标Fragment
*/
private void removeFragmentInternal(BaseFragment fragment) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.remove(fragment);
transaction.commitNow();
} /**
* 此方法不用position做返回值即可破解fragment tag异常的错误
*/
@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<BaseFragment> getFragments() {
return mFragmentList;
}
}

测试代码:

 public class TestActivity extends FragmentActivity implements View.OnClickListener {
List<Fragment> mFragmentList;
ViewPager mViewPager;
public BaseFragmentPagerAdapter mAdapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
mViewPager = findViewById(R.id.vp);
findViewById(R.id.btn_change).setOnClickListener(this); mFragmentList = new ArrayList<>();
mFragmentList.add(getFg("AAA"));
mFragmentList.add(getFg("BBB"));
mFragmentList.add(getFg("CCC"));
mFragmentList.add(getFg("DDD"));
mAdapter = new BaseFragmentPagerAdapter(getSupportFragmentManager(), mFragmentList);
mViewPager.setAdapter(mAdapter);
} private TestFragment getFg(String a){
TestFragment fragment = new TestFragment();
fragment.setTest(a);
return fragment;
} @Override
public void onClick(View view) {
TestFragment eee = getFg("EEE"); //新增
mAdapter.addFragment(eee);
//插入
mAdapter.insertFragment(1, eee); //删除
mAdapter.removeFragment(1);
//删除
mAdapter.removeFragment(mFragmentList.get(1)); //替换
mAdapter.replaceFragment(1, eee);
//替换
mAdapter.replaceFragment(mFragmentList.get(0), eee);
}
}

内容取自

https://blog.csdn.net/lyabc123456/article/details/79797552

Android-FragmentPagerAdapter刷新无效的解决方案的更多相关文章

  1. FragmentPagerAdapter刷新fragment最完美解决方案

    FragmentPagerAdapter刷新fragment最完美解决方案   先感谢kingjxl2006的博客文章<Android FragmentPagerAdapter数据刷新notif ...

  2. Android查缺补漏(View篇)--自定义 View 中 wrap_content 无效的解决方案

    自定义 View 中 wrap_content 无效的解决方案 做过自定义 View 的童鞋都会发现,直接继承 View 的自定义控件需要重写 onMeasure() 方法,并设置 wrap_cont ...

  3. Android 启动APP黑屏解决方案

    #Android 启动APP黑屏解决方案# 1.自定义Theme //1.设置背景图Theme <style name="Theme.AppStartLoad" parent ...

  4. Android大图片裁剪终极解决方案(上:原理分析)

    转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-)  http://my.oschina.net/ryanhoo/blog/86842 约几个月前,我正 ...

  5. Android界面刷新方法

    Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中 ...

  6. Android开发——Android M(6.0) 权限解决方案

    Android开发--Android M(6.0) 权限解决方案 自从Android M(6.0)发布以来,权限管理相比以前有了很大的改变,很多程序员发现之前运行的好好的Android应用在Andro ...

  7. Atitit. IE8.0 显示本地图片预览解决方案 img.src=本地图片路径无效的解决方案

    Atitit. IE8.0 显示本地图片预览解决方案 img.src=本地图片路径无效的解决方案 1. IE8.0 显示本地图片 img.src=本地图片路径无效的解决方案1 1.1. div来完成  ...

  8. Android终端与服务器数据传输解决方案

    Android终端与服务器数据传输解决方案 Android终端三种与服务器传输方式:   Socket传输 WebService传输 Post/Get获取数据方式 网络实现条件 端口:指定 协议:TC ...

  9. 支持WEB、Android、IOS的地图解决方案

    转自原文 支持WEB.Android.IOS的地图解决方案 工具链 GIS工具集 OpenGeo Suite 包含PostGIS, GeoServer, GeoWebCache, OpenLayers ...

随机推荐

  1. Atitit 图像处理 halcon类库的使用  范例边缘检测 attilax总结

    Atitit 图像处理 halcon类库的使用  范例边缘检测 attilax总结 1.1. 安装halcon11 ..体积大概1g压缩模式1 1.2. Halcon的科技树1 1.3. 启动 &qu ...

  2. django——文件上传_分页_ajax_富文本_celery

    上传文件 概述 当Django在处理文件上传时,文件的数据被存储在request.FILES属性中 FILES只有在请求的方法为POST且提交的form表单带有enctype="multip ...

  3. CCAction、CCFiniteTimeAction、CCSpeed、CCFollow

    /**************************************************************************** Copyright (c) 2010-201 ...

  4. 每日英语:Are Smartphones Turning Us Into Bad Samaritans?

    In late September, on a crowded commuter train in San Francisco, a man shot and killed 20-year-old s ...

  5. 整理Lua和Unity和Lua交互文章链接

    重点文章: 1.[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(上) 2.[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(中) 3.Lua和C++交互详细总结 4. ...

  6. Lua语法基础(2)--基本语法、函数

    上一篇编辑编辑着,发现,缩进出了问题.作为一个不是强迫症的人,实在是忍受不了同一级内容不同缩进方式的槽点,于是重开一篇吧.(万幸,这样的文章也只有我自己看.) 第四 基本语法 赋值语句,Lua可以对多 ...

  7. 【Socket】linux广播技术

    1.mystery引入        1)本学期学的ARP协议和NTP协议都属于广播技术的实现,所以借此机会了解下广播技术的底层原理    2)在IP地址中,如果最后一个数字为255,则一定是一个广播 ...

  8. js如何获取前后连续n天的时间

    function GetDateStr(AddDayCount) { var dd = new Date(); dd.setDate(dd.getDate()+AddDayCount);//获取Add ...

  9. audio音乐播放

    1.audio标签 <audio @play="ready" @error="error" ref="audio" :src=&quo ...

  10. linux输入子系统

    linux输入子系统(linux input subsystem)从上到下由三层实现,分别为:输入子系统事件处理层(EventHandler).输入子系统核心层(InputCore)和输入子系统设备驱 ...