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

ops/2024/12/26 11:19:37/

在使用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.ppmy.cn/ops/145113.html

相关文章

排序算法(系列)

希尔排序(Shell Sort)是一种插入排序的改进版本。它是基于插入排序的思想,通过将待排序的元素进行分组,然后对每组进行插入排序,逐步减少分组的大小,最终完成排序。希尔排序的核心思想是将序列分为多个子序…

赛博错题本

机构抽象老师非得让我们整一个错题本,我寻思都学计算机了,还在整高中做题呢一套是什么意思呢,更何况考试也就一周一次,你整个本完完全全没有必要,整个赛博错题本得了。以后错题都会存在这里,基本上一周一更…

C#中的属性索引器(Indexer)

属性索引器(Indexer)是C#中一个非常有用的特性,它允许类的实例像数组一样通过索引进行访问。索引器不仅限于整数索引,还可以使用其他类型,如字符串,作为索引键。这使得索引器在访问集合类型或需要通过键来访…

[源码解析] 模型并行分布式训练Megatron (2) --- 整体架构

link [源码解析] 模型并行分布式训练Megatron (2) --- 整体架构 目录 [源码解析] 模型并行分布式训练Megatron (2) --- 整体架构 0x00 摘要0x01 启动 1.1 分布式启动1.2 构造基础 1.2.1 获取模型1.2.2 获取数据集1.2.3 步进函数 1.2.3.1 广播数据0x02 Pretrain0x03 初始化 3.1 …

Go语言中context 结构原理, 使用场景和用途

Go语言中context结构原理 在Go语言中,context是一个用于在API边界之间传递请求范围的值、取消信号、截止时间等信息的机制。它主要用于处理跨API边界的请求取消、超时控制以及传递请求范围内的共享数据。context的设计目标是为了解决在并发编程中,特别是…

SAM大模型实践(六)

今天试了一下geo-SAM快速版本fast-sam,项目参考地址如下: https://samgeo.gishub.org/examples/fast_sam/https://samgeo.gishub.org/examples/fast_sam/具体代码如下: # %pip install segment-geospatial segment-anything-fast # 在conda…

【Java基础面试题025】什么是Java的Integer缓存池?

回答重点 Java的Integer缓存池(Integer Cache)是为了提升性能和节省内存。根据实践发现大部分的数据操作都集中在值比较小的范围,因此缓存这些对象可以减少内存分配和垃圾回收的负担,提升性能 在 -128到127范围内的Integer对象会…

常见网络攻击场景常被用于测试系统安全性

常见网络攻击场景常被用于测试系统安全性 在区块链系统中,以下网络攻击场景常被用于测试系统安全性: 51% 攻击 攻击原理:当一个或一组攻击者控制了超过全网 50%的算力时,就有可能操纵区块链的账本记录。在工作量证明(PoW)机制下,攻击者可以通过算力优势,实现对新区块的…