当前位置: 首页 > article >正文

Android笔记:解决fragment+viewpager第二次进入的时候没有数据的问题

在使用ViewPager结合Fragment时,如果第二次无法显示,可能是因为FragmentManager没有正确处理Fragment的状态,或者ViewPager的适配器没有正确处理Fragment的生命周期。

解决方法:

确保你的FragmentPagerAdapter或FragmentStatePagerAdapter重写了getItemPosition()方法,并在Fragment数据改变时返回POSITION_NONE。

使用FragmentStatePagerAdapter而不是FragmentPagerAdapter,因为它能够保存和恢复Fragment的状态,有助于解决内存问题和确保第二次能够正确显示。

确保在适配器中正确实现了getCount()方法,以便ViewPager可以为每一个页面创建或者重用Fragment。

如果你在Fragment的生命周期中做了某些数据初始化或者界面更新的操作,确保这些操作在Fragment可见的情况下进行,例如在onResume()方法中。

如果你使用的是Fragment的回退栈,确保在适配器的getItem()方法中,对于已经存在的Fragment没有重新创建新的实例,而是使用了回退栈中的实例。

如果你在Fragment的onCreateView()方法中进行了布局的初始化,确保你在onCreateView()的布局被请求时,布局是被正确地创建和返回的。

如果你在ViewPager的setAdapter()之后做了任何可能影响Fragment状态的操作,确保这些操作在ViewPager完全设置好之后进行。

如果你在Activity的onCreate()中设置了ViewPager的适配器,确保这个调用是在Activity的onResume()或之后的生命周期中进行的。

如果以上步骤仍然不能解决问题,可以考虑使用日志或调试工具来跟踪Fragment的生命周期和ViewPager适配器的行为,以便找到问题的根源。

有的 建议不用 FragmentPagerAdapter,而改用 FragmentStatePagerAdapter,并且重载 getItemPosition() 并返回 POSITION_NONE,以触发销毁对象以及重建对象。从上面的分析中看,后者给出的建议确实可以达到调用 notifyDataSetChanged() 后,Fragment 被以新的参数重新建立的效果。

但是问题在于,如果我们只能这么解决这个问题,岂不是 FragmentPagerAdapter 就用不上了?最关键的是,二者对应的情况不同。对于页面相对较少的情况,我仍旧希望能够将生成的 Fragment 保存在内存中,在需要显示的时候直接调用,而不要产生生成、销毁对象的额外的开销,这样效率更高。这种情况下,选择 FragmentPagerAdapter 是更适合,不加考虑的选择 FragmentStatePagerAdapter 是不合适的。我们不能够因噎废食。

因此,对于 FragmentPagerAdapter 的解决方案就是,分别重载 getItem() 以及 instantiateItem() 对象。getItem() 只用于生成新的与数据无关的 Fragment;而 instantiateItem() 函数则先调用父类中的 instantiateItem() 取得所对应的 Fragment 对象,然后,根据对应的数据,调用该对象对应的方法进行数据设置。

当然,不要忘记重载 getItemPosition() 函数,返回 POSITION_NONE,这个两个类的解决方案都需要的。二者不同之处在于,FragmentStatePagerAdapter 在会在因 POSITION_NONE 触发调用的 destroyItem() 中真正的释放资源,重新建立一个新的 Fragment;而 FragmentPagerAdapter 仅仅会在 destroyItem() 中 detach 这个 Fragment,在 instantiateItem() 时会使用旧的 Fragment,并触发 attach,因此没有释放资源及重建的过程。

这样,当 notifyDataSetChanged() 被调用后,会最终触发 instantiateItem(),而不管 getItem() 是否被调用,我们都在重载的 instantiateItem() 函数中已经将所需要的数据传递给了相应的 Fragment。在 Fragment 接下来的 onCreateView(), onStart() 以及 onResume() 的事件中,它可以正确的读取新的数据,Fragment 被成功复用了。

这里需要注意一个问题,在 Fragment 没有被添加到 FragmentManager 之前,我们可以通过 Fragment.setArguments() 来设置参数,并在 Fragment 中,使用 getArguments() 来取得参数。这是常用的参数传递方式。但是这种方式对于我们说的情况不适用。因为这种数据传递方式只可能用一次,在 Fragment 被添加到 FragmentManager 后,一旦被使用,我们再次调用 setArguments() 将会导致 java.lang.IllegalStateException: Fragment already active 异常。因此,我们这里的参数传递方式选择是,在继承的 Fragment 子类中,新增几个 setter,然后通过这些 setter 将数据传递过去。反向也是类似。相关信息可以参考 [5]。哦,这些 setter 中要注意不要操作那些 View,这些 View 只有在 onCreateView() 事件后才可以操作。

针对 FragmentPagerAdapter 的解决办法如下列代码所示:

 1 @Override
2 public Fragment getItem(int position) {
3     MyFragment f = new MyFragment();
4     return f;
5 }
6 
7 @Override
8 public Object instantiateItem(ViewGroup container, int position) {
9     MyFragment f = (MyFragment) super.instantiateItem(container, position);
10     String title = mList.get(position);
11     f.setTitle(title);
12     return f;
13 }
14 
15 @Override
16 public int getItemPosition(Object object) {
17     return PagerAdapter.POSITION_NONE;
18 }

http://www.kler.cn/a/449441.html

相关文章:

  • dockerfile文档编写(3):构建失败后清理缓存(删除容器和镜像相关命令)
  • 责任链模式(ChainofResponsibilityPattern)
  • 软件测试工程师撰写优质测试用例的秘籍
  • Linux 环境搭建(云服务器和XShell)
  • C# Random 随机数 全面解析
  • SpringBoot——核心概念
  • 【国产NI替代】基于全国产FPGA的16振动+2转速+8路IO口输入输出(24bits)256k采样率,高精度终端采集板卡
  • 再服务器上建立新的编译环境
  • ubuntu18.04升级到ubuntu20.04
  • WPF+MVVM案例实战与特效(四十六)- 打造动态背景时钟控件,轻松提升界面美感
  • Android 代码模式的理解
  • Flamingo:少样本多模态大模型
  • 目标检测-R-CNN
  • Pytorch | 利用EMI-FGSM针对CIFAR10上的ResNet分类器进行对抗攻击
  • 【阅读记录-章节6】Build a Large Language Model (From Scratch)
  • c# 不同数据类型转换
  • uniapp-微信小程序调用摄像头
  • springboot474基于web的垃圾分类回收系统(论文+源码)_kaic
  • 低代码开源项目Joget的研究——安装部署
  • 动态规划<四> 回文串问题(含对应LeetcodeOJ题)