一次开发中,用到了viewpager嵌套viewpager,结果就踩到了这么一个坑。

先上图:

image.png

图片中显示的界面布局和遇到的问题是这样的:首页发现版块是一个fragment,这个fragment中放了一个viewpager,这个viewpager有三页,其中最后一页对应的fragment又放了一个viewpager,内层的viewpager有两页。进入发现时,从外层viewpager第一页切到第三页,加载内层viewpager第一页的数据,然后切回外层viewpager第一页,当再次切到外层viewpager第三页时,出现了神奇的一幕,之前加载的内层viewpager第一页界面展示的数据神奇的不见了。

好吧,我自己都被说晕了,反正大概就是这么一个情况。

首先我外层viewpager和内层viewpager用的adapter都是继承自FragmentStatePagerAdapter,viewpager的默认缓存页为1,因此首先我可以确认的是,外层viewpager在第一页和第三页切换显示时,fragment会有销毁和创建。当外层viewpager从第三页切回第一页时,此时第三页的fragment被释放,正常的逻辑是第三页fragment内层的viewpager包含的两个fragment也是被释放的,当然,这也只是理论上的。为了验证自己的猜想,我在对应fragment onDestory方法中写一条Log,下面是控制台输出的截图:

logcat.png

Log的显示验证了我的猜想,所以问题到底出在哪里呢?我们继续写Log,这次我们把外层viewpager第三页的fragment和内层viewpager第一页fragment内存地址输出来:

first.png

second.png

比较来回切换两次的控制台信息我们可以看到,外层viewpager第三页的fragment内存地址没有变化,因为viewpager数据源没有变,fragment只是重走了生命周期,而fragment重新走生命周期时,内层viewpager对应的数据源是重新创建的,控制台打印的内层viewpager第一页fragment内存地址不一样正好验证了这是两个fragment,既然两个对象都不一样,fragment重新创建,数据重新加载,就不存在界面数据不显示的问题,可是结果并不是我想的那样,这就尴尬了!

冷静的思考了一下,既然fragment是重新创建的,会不会出现adapter返回的fragment不一致呢?继续写Log:

first1.png

second1.png

看完Log我惊呆了,第二次重新创建了fragment,但是adapter竟然没有返回fragment,wtf???那adapter没有返回fragment,界面显示的fragment哪里来的呢?第一反应想的是不是适配器有缓存,切回来时直接走的缓存,查阅FragmentStatePagerAdapter源码,果不其然,被我找到了!源码如下:

@Override

public Parcelable saveState() {

Bundle state = null;

if (mSavedState.size() > 0) {

state = new Bundle();

Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];

mSavedState.toArray(fss);

state.putParcelableArray("states", fss);

}

for (int i=0; i

Fragment f = mFragments.get(i);

if (f != null && f.isAdded()) {

if (state == null) {

state = new Bundle();

}

String key = "f" + i;

mFragmentManager.putFragment(state, key, f);

}

}

return state;

}

@Override

public void restoreState(Parcelable state, ClassLoader loader) {

if (state != null) {

Bundle bundle = (Bundle)state;

bundle.setClassLoader(loader);

Parcelable[] fss = bundle.getParcelableArray("states");

mSavedState.clear();

mFragments.clear();

if (fss != null) {

for (int i=0; i

mSavedState.add((Fragment.SavedState)fss[i]);

}

}

Iterable keys = bundle.keySet();

for (String key: keys) {

if (key.startsWith("f")) {

int index = Integer.parseInt(key.substring(1));

Fragment f = mFragmentManager.getFragment(bundle, key);

if (f != null) {

while (mFragments.size() <= index) {

mFragments.add(null);

}

f.setMenuVisibility(false);

mFragments.set(index, f);

} else {

Log.w(TAG, "Bad fragment at key " + key);

}

}

}

}

}

当传入FragmentStatePagerAdapter的数据源不为空,viewpager在被销毁时,FragmentStatePagerAdapter会自动保存数据;我们接着写Log看看这两个方法到底有没有走:

first2.png

second2.png

果然,FragmentStatePagerAdapter在外层viewpager第三页fragment销毁时保存了状态,再次切回来时,虽然fragment重走了生命周期,但是由于FragmentStatePagerAdapterde直接取的缓存,销毁时只保存了fragment的状态,切回时缓存的fragment状态恢复,但是数据源已经释放,从而导致界面数据不显示。

至此,我们终于找到了bug罪魁祸首!所以这个问题的解决方案是去掉FragmentStatePagerAdapterde 缓存,具体代码如下:

public class BaseFragmentPageAdapter extends FragmentStatePagerAdapter {

public BaseFragmentPageAdapter(FragmentManager fm) {

super(fm);

}

@Override

public Fragment getItem(int position) {

return null;

}

@Override

public int getCount() {

return 0;

}

@Override

public Parcelable saveState() {

return null;

}

@Override

public void restoreState(Parcelable state, ClassLoader loader) {

}

}

讲了这么多,不知道各位有没有看懂!

android fragmentstatepageradapter框架,安卓爬坑指南之FragmentStatePagerAdapter相关推荐

  1. 蓝牙BLE(BlueTooth BLE)入门及爬坑指南

    前言 最近比较忙,两三周没有更新简书了,公司正好在做蓝牙BLE的项目,本来觉得挺简单的东西从网上找了个框架,就咔咔地开始搞,搞完以后才发现里面还有不少坑呢,故而写一篇蓝牙BLE入门及爬坑指南,旨在帮助 ...

  2. JWT 入坑爬坑指南

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | 公众号「程序新世界」 越来越多的开发者开始学习 ...

  3. paddlepaddle 人脸识别爬坑指南

    综述 爬坑一天,整出来一套还行的方案,特此分享爬坑心得~ 因为整体代码结构和上篇手写数字的文章里代码结构比较相似,所以这里只贴出部分代码 网络结构 目前采用的两套模型是普通cnn以及vgg,效果不错, ...

  4. 从《编程之美》买票找零问题说起,娓娓道来卡特兰数——兼爬坑指南

    转自:从<编程之美>买票找零问题说起,娓娓道来卡特兰数--兼爬坑指南 引子: 大约两个月前,我在练习一些招聘的笔试题中,有一道和卡特兰数相关.那时还没来得及开始仔细看<编程之美> ...

  5. 微信公众号JS-SDK多图上传爬坑指南

    一.wx.chooseImage爬坑 出现的问题: 安卓将chooseImage 方法返回的 localId 放在img标签的src属性下能够显示图片 IOS将chooseImage 方法返回的 lo ...

  6. 开发工具总结(2)之全面总结Android Studio2.X的填坑指南

    前言:好多 Android 开发者都在说Android Studio太坑了,老是出错,导致开发进度变慢,出错了又不知道怎么办,网上去查各种解决方案五花八门,有些可以解决问题,有些就是转来转去的写的很粗 ...

  7. Nuxt(安装部署)爬坑指南

    Nuxt.js使用详细说明 这篇文章主要向大家介绍Nuxt爬坑,主要内容包括基础应用.实用技巧.原理机制等方面,希望对大家有所帮助. https://www.shangmayuan.com/a/dcd ...

  8. iOS-通俗易懂的微信支付接入和爬坑指南,十分钟轻松搞完

     现在基本所有的App都会接入支付宝支付以及微信支付,也有很多第三方提供给你 SDK帮你接入,但是这种涉及到支付的东西还是自己服务器搞来的好一些,其实搞懂了 逻辑非常的简单,下面直接给大家说说下基本流 ...

  9. android手机屏幕共享神器踩坑指南

    开源项目地址:https://github.com/Genymobile/scrcpy scrcpy,由 Genymobile 推出的可跨平台的.可自定义码率的.开源的屏幕共享工具.它提供了在 USB ...

最新文章

  1. 2021年春季学期-信号与系统-第三次作业参考答案-第十一道题
  2. 机器学习(MACHINE LEARNING) 【周志华版-”西瓜书“-笔记】 DAY13-半监督学习
  3. Spring 学习04
  4. 45张令程序员泪流满面的趣图
  5. C++智能指针(三)总结
  6. java将某个数按比例分配应用题,按比例分配应用题
  7. jQuery常用方法总结(转)
  8. usd php 换算,货币在PHP中从INR转换为USD
  9. win2003(sp2 x86)+iis6+php-5.3.5-Win32 配置
  10. ai音响怎么连接网络_网络适配器未连接怎么办
  11. 服务器中文档存储在哪,云服务器存储在哪
  12. MacOS Monterey 12.5.1 (21G83) OC 0.8.4 / Cl 5148 / PE 三分区原版黑苹果镜像
  13. html两个部分组成部分组成,html页面由哪几部分组成
  14. word文件打不开怎么办?显示的是:调试,发送错误报告,不发送
  15. 【时间之外】原来春节抽红包是这样实现的
  16. python电商_电商数据分析(python)
  17. umap算法_科学网—[转载]【源码】均匀流形近似与投影(UMAP)算法仿真 - 刘春静的博文...
  18. '操作必须使用一个可更新的查询'解决方法
  19. pta 软硬车厢交替排列
  20. highCharts滚动条在火狐浏览器中的坑

热门文章

  1. .NET Core 2.1 Preview 2发布 - April 10, 2018
  2. TypeScript 2.5 发布,增加语言级重构
  3. 分布式事务,EventBus 解决方案:CAP【中文文档】
  4. 统一的.NET文档体验发布
  5. java用log.i打印数组_java-使用JSCH将ssh日志打印到列表(android)
  6. XunSearch的安装和加入服务器开机脚本以及将目录写入系统变量
  7. 清除谷歌浏览器的dns缓存
  8. 让VS Code 支持 Jupyter Notebook
  9. 基于JavaScript 数组的经典程序应用源码(强烈建议收藏)
  10. 【计算机图形学】实验:C#.net环境下采用GDI+图形特技处理案例教程