Android-FragmentPagerAdapter刷新无效的解决方案,dubbo经典面试题

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

这里写图片描述

此时列表中只剩下A C D三个Fragment, 那么前面提到过,此时getItemPpsition()方法我们应该做的是A对应的Fragment返回POSITION_UNCHANGED, 因为A的位置没有发生变化,而B(已删除)、 C(移位) 、 D(移位) 三个我们应该返回POSITION_NONE,因此我们的adapter在刷新的时候刷新到第二个位置时会再首先去查找对应tag的Fragment:

这里写图片描述

此时查找的tag是C1,然而找不到,因为C前面add的tag是C2,所以走else, 在else当中就会从我们的列表中去get第1个item,那取到的自然是C,然后对C进行add操作,这时又会生成C对应的tag传入add()方法,但是此时,注意了,生成C的tag的方法生成的结果是C1(fragment的id+当前position),分析到这里你可能发现了,前面我们的C是被add过的,所以之前C的mTag是C2,到了这里add操作时要变成C1了!所以跟着源码走进去自然就符合前面“Can’t change tag of fragment “异常的判断条件fragment.mTag != null &&!tag.equals(fragment.mTag),我们的C之前的mTag不为空并且C1 != C2,所以中标了!

那么解决问题的方法,首先想到的是为每一个Fragment设置一个唯一的tag值,但是mTag在Fragment源码中是protected的,我们是不能改的。。。所以只能去改生成tag的方法makeFragmentName()了,但是一看这个方法又是private的,又不能改。。。。我TMD…CNM…MMP…好吧,再看,因为makeFragmentName()方法用到了getItemId()的返回值,而getItemId()我们是可以重写的,所以那去只能改getItemId()方法了:

@Override

public long getItemId(int position) {

// return position;

return 我们自定义的可以确定当前item的唯一值;

}

因为前面提到过getItemId()方法默认返回的是position,所以我们这个方法要修改一下,返回一个唯一的值,一个可以标志这个fragment的唯一值就可以了,这样在删除操作position发生变化之后,C的tag值经过makeFragmentName()生成的结果总是C+uniqueId, 所以应该不会有问题了。

好了,至此所有问题思路解决完毕,贴一下完善FragmentPagerAdapter的完整代码:

/**

  • 加载显示Fragment的ViewPagerAdapter基类

  • 提供可以刷新的方法

  • @author Fly

  • @e-mail 1285760616@qq.com

  • @time 2018/3/22

*/

public class BaseFragmentPagerAdapter extends FragmentPagerAdapter {

private List mFragmentList;

private FragmentManager mFragmentManager;

/*下面两个值用来保存Fragment的位置信息,用以判断该位置是否需要更新/

private SparseArray mFragmentPositionMap;

private SparseArray mFragmentPositionMapAfterUpdate;

public BaseFragmentPagerAdapter(FragmentManager fm, List 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 getFragments() {

return mFragmentList;

}

}

好了,现在这个类可以用来实现Fragment列表中的Fragment替换、删除、添加等操作了,并且可以实时刷新adapter, 你可以试验一下。

测试代码:

Activity代码

public class TestActivity extends FragmentActivity implements View.OnClickListener {

List 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;

}

总结

可以看出,笔者的工作学习模式便是由以下 「六个要点」 组成:

❝ 多层次的工作/学习计划 + 番茄工作法 + 定额工作法 + 批处理 + 多任务并行 + 图层工作法❞

希望大家能将这些要点融入自己的工作学习当中,我相信一定会工作与学习地更富有成效。

下面是我学习用到的一些书籍学习导图,以及系统的学习资料。每一个知识点,都有对应的导图,学习的资料,视频,面试题目。

**如:我需要学习 **Flutter的知识。(大家可以参考我的学习方法)

  • Flutter 的思维导图(无论学习什么,有学习路线都会事半功倍)

  • Flutter进阶学习全套手册

  • Flutter进阶学习全套视频

大概就上面这几个步骤,这样学习不仅高效,而且能系统的学习新的知识。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

。(大家可以参考我的学习方法)

  • Flutter 的思维导图(无论学习什么,有学习路线都会事半功倍)

[外链图片转存中…(img-6En3f521-1713693698776)]

  • Flutter进阶学习全套手册

[外链图片转存中…(img-ZckxJMkX-1713693698776)]

  • Flutter进阶学习全套视频

[外链图片转存中…(img-vL7OBAE9-1713693698776)]

大概就上面这几个步骤,这样学习不仅高效,而且能系统的学习新的知识。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-ObHG8cFc-1713693698777)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 16
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值