Android-FragmentPagerAdapter刷新无效的解决方案
按照通常使用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刷新无效的解决方案的更多相关文章
- FragmentPagerAdapter刷新fragment最完美解决方案
FragmentPagerAdapter刷新fragment最完美解决方案 先感谢kingjxl2006的博客文章<Android FragmentPagerAdapter数据刷新notif ...
- Android查缺补漏(View篇)--自定义 View 中 wrap_content 无效的解决方案
自定义 View 中 wrap_content 无效的解决方案 做过自定义 View 的童鞋都会发现,直接继承 View 的自定义控件需要重写 onMeasure() 方法,并设置 wrap_cont ...
- Android 启动APP黑屏解决方案
#Android 启动APP黑屏解决方案# 1.自定义Theme //1.设置背景图Theme <style name="Theme.AppStartLoad" parent ...
- Android大图片裁剪终极解决方案(上:原理分析)
转载声明:Ryan的博客文章欢迎您的转载,但在转载的同时,请注明文章的来源出处,不胜感激! :-) http://my.oschina.net/ryanhoo/blog/86842 约几个月前,我正 ...
- Android界面刷新方法
Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中 ...
- Android开发——Android M(6.0) 权限解决方案
Android开发--Android M(6.0) 权限解决方案 自从Android M(6.0)发布以来,权限管理相比以前有了很大的改变,很多程序员发现之前运行的好好的Android应用在Andro ...
- Atitit. IE8.0 显示本地图片预览解决方案 img.src=本地图片路径无效的解决方案
Atitit. IE8.0 显示本地图片预览解决方案 img.src=本地图片路径无效的解决方案 1. IE8.0 显示本地图片 img.src=本地图片路径无效的解决方案1 1.1. div来完成 ...
- Android终端与服务器数据传输解决方案
Android终端与服务器数据传输解决方案 Android终端三种与服务器传输方式: Socket传输 WebService传输 Post/Get获取数据方式 网络实现条件 端口:指定 协议:TC ...
- 支持WEB、Android、IOS的地图解决方案
转自原文 支持WEB.Android.IOS的地图解决方案 工具链 GIS工具集 OpenGeo Suite 包含PostGIS, GeoServer, GeoWebCache, OpenLayers ...
随机推荐
- Android 3.0开始引入fragments(碎片、片段)类
Fragment要点 Fragment作为Activity界面的一部分组成出现. 可以在一个Activity中同时出现多个Fragment,并且,一个Fragment亦可在多个Activity中使用. ...
- 解决Maven->update project 恢复为默认jdk1.5以及One or more constraints have not been satisfied问题
使用maven架构创建dynamic web 项目之后,默认指定的jdk 和compilerVersion都非常古老,而且即便你手动更新了版本之后,每次update project都会复位,非常不爽. ...
- [Unity3D]Unity3D游戏开发之跑酷游戏项目解说
大家好,我是秦元培.我參加了CSDN2014博客之星的评选,欢迎大家为我投票,同一时候希望在新的一年里大家能继续支持我的博客. 大家晚上好.我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.c ...
- mac 上面安装jdk 1.6
下载地址 https://support.apple.com/kb/dl1572?locale=zh_CN orcale 支持mac的最低版本是1.7
- IBAction:IBOutlet:注意事项
1.IBAction: 1> 能保证方法能够连线 > 相当于void 2.IBOutlet: 1> 能保证属性能够连线 3.常见错误 setValue:forUndefinedKey ...
- nginx 前端调度 对后端的app的生存状态的检测
# cat hosts.conf #app调试 upstream gl-appsrv_pools { server 10.1x0.2xx.1x0:8040; server 10.x9x.20.208: ...
- 菜鸟调错(六)——Hibernate 4.3.x 注解常见错误及解决方案
编程的过程免不了遇到各种错误,各种问题,而遇到问题,解决问题的这个过程我认为是最让人兴奋的事情.越棘手的问题,解决以后带来的快感也越大.当一个问题你搞了一下午或者一天,甚至几天,当你解决的那一刻你会觉 ...
- How do I learn mathematics for machine learning?
https://www.quora.com/How-do-I-learn-mathematics-for-machine-learning How do I learn mathematics f ...
- .NET MVC5+ EF+AutoFac自动注入框架
1.创建一个MVC系统 VIEW显示页面代码: <link href="~/Content/bootstrap.css" rel="stylesheet" ...
- javascript基础拾遗(四)
1.什么是闭包 正常函数,执行完毕后相关的参数,变量就释放掉了. 当一个函数的返回值是另一个函数时,该函数的相关参数和变量都会保存在返回的函数中,这种结构叫做闭包. 2.示例 计算数组和 functi ...