FragmentPagerAdapter 的那些坑

Android - 一种新奇的冷启动速度优化思路(Fragment极度懒加载 + Layout子线程预加载) 众所周知,Context是一个抽象类,实现它的包装类就是ContextWrapper,而Activity、Appcation等都是ContextWrapper的子类,然而,ContextWrapper还有一个神奇的子类,直接看图,这个是首页四个子Tab Fragment的基类的layout,因为某些东西设计的不合理,导致层级是非常的深,直接导致了首页上的三个tab加上FeedMainFragment自身,光将这个View inflate出来的时间就非常长。因此,我们就产生了懒加载这样一个说法。 阅读详情

引子

image

开始前,首先来看一下这种常用的布局,每个底部导航栏项中呢都有一个ViewPager。
笔者先来说一下自己遇到的问题,第一次进入的时候ViewPager(第一页)显示正常,但是切换到别的底部tab再切换回来的时候,ViewPager的第一项和第二项的视图就没有了,试过FragmentPagerAdapter 和 FragmentStatePagerAdapter 但都没有解决问题,所以笔者决定从源码的角度出发,去探索问题所在。

起始

首先
底部Tab1是HomeFragement
底部Tab2是OrdersFragment

由HomeFragment切换到OrdersFragment之后的周期调用情况如下:

— 后台打印如下 —
07-29 11:21:56.560 18830-18830/com.finobusiness.forhomelife D/HomeFragment: onDestroyView:
07-29 11:21:56.565 18830-18830/com.finobusiness.forhomelife D/OrdersFragment: onCreateView:

HomeFragment只是调用了onDestroyView方法,没有调用onDestroy方法。

问题源头

FragmentPagerAdapter 的instantiateItem()方法如下:

 @Override
    public Object instantiateItem(ViewGroup container, int position) {

        final long itemId = getItemId(position);

        // Do we already have this fragment?
        String name = makeFragmentName(container.getId(), itemId);
        Fragment fragment = mFragmentManager.findFragmentByTag(name);
        if (fragment != null) {
            mCurTransaction.attach(fragment);
        } else {
            fragment = getItem(position);
            mCurTransaction.add(container.getId(), fragment,
                    makeFragmentName(container.getId(), itemId));
        }

        return fragment;
    }

需要注意的是这段代码:

        Fragment fragment = mFragmentManager.findFragmentByTag(name);

可以看到在去实例化一个Fragment之前会先去FragmentManager当中通过Tag查找是否已经有了这个Fragment,如果有,则不再调用public abstract Fragment getItem(int position) 这个方法,通常这是咱们实现的用来提供Fragment的方法。

Fragment 的 onDestroyView()

因为ViewPager当中的Fragment的视图已经被销毁了

onDestroyView的源码

    public void onDestroyView() {
        mCalled = true;
    }

没错,只有这么一行,但是里面的mCalled威力可是很惊人的,一会儿就会涉及到。
在代码中查询,发现onDestroyView()方法在全局中只有一个地方被调用到了,那就是

 void performDestroyView() {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchDestroyView();
        }
        mState = CREATED;
        mCalled = false;
        onDestroyView();
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onDestroyView()");
        }
        if (mLoaderManager != null) {
            mLoaderManager.doReportNextStart();
        }
    }

首先呢可以看到如果onDestroyView()方法在在子类中没有被调用,则会抛出SuperNotCalledException异常

其次

mChildFragmentManager.dispatchDestroyView 最终会调用到FragmentManager的void moveToState(int newState, int transit, int transitStyle, boolean always)方法。

moveToState方法的源码如下

    void moveToState(int newState, int transit, int transitStyle, boolean always) {
        mCurState = newState;
        if (mActive != null) {
            boolean loadersRunning = false;
            for (int i=0; i<mActive.size(); i++) {
                Fragment f = mActive.get(i);
                if (f != null) moveToState(f, newState, transit, transitStyle, false);
            }
        }
    }
    case Fragment.ACTIVITY_CREATED:
            if (newState < Fragment.ACTIVITY_CREATED) {

                f.performDestroyView();
                if (f.mView != null && f.mContainer != null) {
                    f.mContainer.removeView(f.mView);
                }
                f.mContainer = null;
                f.mView = null;
                f.mInnerView = null;
    }

最终可以看到fragment.view被移除并且被置为null。
下一次进来的时候Fragment被通过getFragmentByTag方法找到,但是他的View却是空,所以我们的ViewPager的前两页(默认的缓存页)就没有视图。

解决之道

解决的办法就是ViewPager所在的那个Fragment中手动调用PagerAdapter 的destroyItem方法

FragmentPagerAdapter更换、刷新fragment FragmentPagerAdapter可更换fragment、也可刷新fragment 立即下载

相关推荐

从零上手HiAgent:构建能听懂指令的智能体框架实战指南

智能体(Agent)作为人工智能领域的重要范式,正从传统的预设流程自动化转向以目标驱动的自主规划与执行。其核心原理在于利用大语言模型(LLM)作为决策大脑,通过任务规划、工具调用与记忆机制,将模糊的自然语言指令转化为可执行的工作流。这一技术显著提升了人机协作的效率和自然度,其价值在自动化办公、数据分析与智能流程编排等场景中尤为突出。本文聚焦于HiAgent这一具体框架,深入解析其作为智能体开发平台的核心架构,涵盖规划器、执行器、工具集等关键组件,并提供从环境配置、自定义工具开发到复杂任务链构建的完整工程实践

weixin_29266007的博客 889

FragmentPagerAdapter被弃用后的代替方案

FragmentPagerAdapter被弃用后的代替方案完整解决方案。

u011501017的博客 6733

find命令

命令是 Linux/Unix 系统中用于搜索文件和目录的强大工具,支持多种搜索条件组合,并能对搜索结果执行各种操作。以下是其详细说明、常用参数及示例: 搜索路径:指定起始目录(如 、 或 表示当前目录)。 查找条件:基于文件名、类型、大小、时间等属性过滤。 处理动作:对匹配结果执行操作(如打印、删除、执行命令等)。 常用参数及示例 1. 按名称查找 :区分大小写匹配文件名。 :不区分大小写匹配文件名。 2. 按文件类型查找 :指定文件类型。 文件类型: :普通文件 :目录 :符号链接

qiao2458的博客 1136

ViewPager替代----ViewPager2

ViewPage,主要作用是左右切换当前的view,实现滑动切换的效果,开始动手之后才发现,ViewPager的两个适配器FragmentPagerAdapter和FragmentStatePagerAdapter都被谷歌弃用了,故此在网上查了下平替,就看到了ViewPager2。其中,滑动切换图片是新内容,同时结合其他几个组件回顾一下前面所学。可以看到,目前评论内容也是定死在了前台布局,后续再把数据库学完后,再结合Listview等,逐渐形成一个更“像样”的模块。图1:被弃用了的好哥俩。

weixin_44067776的博客 780

手把手教你学Simulink——基于Simulink的轮毂电机独立驱动转矩矢量分配

阐述了轮毂电机独立驱动的核心价值与转矩分配的必要性在 Simulink 中实现了完整的“上层稳定控制 + 下层最优分配”架构对比了三种分配策略在极限工况下的性能差异提供了工程落地的关键考量特斯拉 Cybertruck(后轮双电机矢量控制)Rivian R1T(四电机坦克掉头)宝马 iX(精准牵引力控制)核心思想“以软件定义底盘,以算法驾驭动力;化四轮之独立,为整车之协同。—— 让汽车在极限边缘依然从容不迫。

MHD0815的博客 369

卷积码Viterbi译码算法原理及C语言实现

具体而言,卷积码的编码过程是将输入数据和编码器中的状态进行异或操作,输出码字为各个状态对应的结果。Viterbi译码算法是一种最大似然译码算法,根据接收到的含有噪声的码字,寻找出最有可能的原始数据序列。(2) 递推计算:根据接收到的码字和当前状态,计算下一时刻各个状态的路径度量,并记录每个状态的前驱状态。以上代码实现了一个简单的卷积码Viterbi译码算法,通过接收到的码字进行译码,并输出解码结果。(1) 初始化:将所有状态的路径度量初始化为一个很大的值,选择路径度量最小的状态作为起始状态。

2301_79331421的博客 826

FragmentPagerAdapter(androidx.fragment.app.FragmentManager)‘ 已被弃用

源代码 public MyAdapter(FragmentManager fragmentManager) { super(fragmentManager); } 改为 public MyAdapter(FragmentManager fragmentManager) { super(fragmentManager,FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT);

qq_38972615的博客 4660

12、无人机系统的建模与仿真

本文深入探讨了无人机系统的建模与仿真技术,涵盖其发展需求、历史演变、动力学建模方法、常用参考框架与状态变量表示,并分析了在控制系统设计、操作员培训和子系统测试中的关键应用。文章还介绍了不同类型无人机(固定翼、旋翼、混合翼)在建模与仿真中的差异,提出了多学科融合、高精度实时仿真及VR/AR技术等未来发展趋势,并给出了实际建模与仿真的标准操作流程,为无人机系统的设计与优化提供了全面的技术支持与展望。

websocket5live的博客 196

ViewPager+Fragment+FragmentPagerAdapter,Fragment无法被销毁

ViewPager+Fragment+FragmentPagerAdapter,Fragment无法被销毁

qq_25330791的博客 828

A算法的蒙特卡洛树搜索

A*算法的蒙特卡洛树搜索 作者:禅与计算机程序设计艺术 1. 背景介绍 在人工智能和游戏开发领域,搜索算法是一个非常重要的研究方向。其中A算法和蒙特卡洛树搜索是两种广泛应用的经典算法。A算法是一种启发式搜索算法,通过评估各个节点到目标节点的启发式代价来引导搜索方向,在

AI天才研究院 1739

解决Home Assistant中安装的Advanced SSH & Web Terminal插件打开提示“502 Bad Gateway” 且弹窗提示“加载项似乎尚未准备就绪,它可能仍在启动中“问题

  在HomeAssistant的应用商店安装了【AdvancedSSH&WebTerminal】插件,但是打开这个终端连接到HomeAssistant的时候却提示“502BadGateway”且弹窗提示“加载项似乎尚未准备就绪,它可能仍在启动中,您想重试吗?”一直无法进入HomeAssistant的系统中

提供C#相关开发 、云计算、运维测试、网络安全相关技术分享与服务,有意向可联系。 2832

ViewPager使用FragmentPagerAdapter 踩坑-不能动态删除Fragment

很多时候我们使用ViewPager来包含Fragment的时候,都是使用FragmentPagerAdapter,大致如下,确实用起来采用官方封装好的PagerAdapter也很简单方便 public class TabFragmentPagerAdapter extends FragmentPagerAdapter { private List&lt;Fragment&gt; mF...

ddxxii的博客 9845

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

viewpager布局复用中FragmentPagerAdapter的坑,源码分析,控件id的一些思考

一个fragment的布局复用,里面是tablayout+viewpager,viewpager加载不同adapter,adapter继承FragmentPageAdapter。运行后有问题,先初始化的fragment正常显示,后加载的fragment里的viewpager全部是空白,这就很尴尬了,第一反应是fragment没add进FragmentManager,因为在同一个activity里,所

秋月夜的博客 2932

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

ViewPager + FragmentPagerAdapter 实现浏览器多窗口遇到的坑

在使用webView开发一个简易浏览器的过程中,需要完成一个浏览器多窗口的功能,我选择使用Viewpager +FragmentPagerAdapter 来实现该功能,但是开发过程中,遇到了下面这两个彼此冲突的问题: 1. 可以成功新建或删除窗口,但是,在新建或删除一个窗口时,其他Fragment中的内容会被刷新,作为浏览器,这样的效果无法令人接受。 2. Frag...

AMD556的博客 556

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

android fragmentpageradapter切换不更新,更新及替换ViewPager中的Fragment 遇到的坑

下图是要实现的效果:星梦缘.png结果我实现的结果:QQ图片20170323170637.pngQQ图片20170323170644.png切换上面的按钮,我希望能够通过调mAdapter.notifyDataSetChanged() 来触发 Fragment 页面使用新的数据调整或重新生成其内容,可是当我调用 notifyDataSetChanged() 后,发现什么都没发生。fragment的...

weixin_36272622的博客 1489

Fragment嵌套带来的坑--页面点击无反应(顺带ViewPager之 FragmentPagerAdapter简单分析)

接手别人的老项目。新版本测试提出一个bug:点击Home最小化的应用—>系统设置界面 改变字体后—>点击进入应用—>3个由viewpager 的fragmentadapter管理的 tab页面点击都没反应。这是一个比较蛋疼的bug,猜想了很多原因,都不对。 项目的结构是 activity 内有mainfragment,mainfragment又 包含viewpager,viewpager 使用Fr

tmac2000的专栏 3779

FragmentPagerAdapter 更新数据遇到了坑啊。下拉刷新不会更新页面、有缓存。

ViewPager+FragmentPagerAdapter:更新Fragment里数据是不起作用,FragmentPagerAdapter添加或减少Fragment时,前面的Fragment内容更新不起作用等等问题,有的做法是暴力删除fragment列表 粗暴解决方案1: List<Fragment> fragments = getSupportFragm

非鹭千里 1197

Android 使用FragmentPagerAdapter懒加载时的坑

       Fragment+ViewPager的方式相信大家经常使用了,但是也有不少的问题。首先就是如果Fragment经常销毁再创建,那样在左右切换的时候界面会显得非常卡顿。         所以我设置setOffscreenPageLimit(count-1),Fragment在add一次后,不再add和remove。         但是一次加载所有的Fragment,尤其当Frag...

zjf375215380的专栏 2053

FragmentPagerAdapter加载fragment并使用setUserVisibleHint()处理预加载时遇到的坑,给textview赋值时出现的空指针异常

FragmentPagerAdapter加载fragment并使用setUserVisibleHint()处理预加载时遇到的坑,给textview赋值时出现的空指针异常

qq_38472465的博客 175

FragmentPagerAdapter加载fragment并使用setUserVisibleHint()处理预加载时遇到的坑,给textview赋值时出现的空指针异常...

FragmentPagerAdapter加载fragment并使用setUserVisibleHint()处理预加载时,给textview赋值时出现的空指针异常 public class BaseFragment extends Fragment { /*布局*/ private View view; /**/ boolean isVisible = ...

weixin_30363817的博客 214

android pageradapter页面缓存,Android ViewPager Adapter 内存管理的坑

好久没有记录bug了的,因为最近一直在解bug... 之所以写这个文章,确实是出于无奈,毕竟同一个问题,项目上遇到了两次。这里主要是提一下 ViewPager + Fragment。ViewPager + Fragment 有 '两种' AdapterFragmentPagerAdapterhttps://developer.android.com/reference/android/suppor...

weixin_39719077的博客 386

Android基础知识-Fragment相关

https://www.jianshu.com/p/d9143a92ad94 https://www.jianshu.com/p/fd71d65f0ec6 一、Fragment生命周期 https://www.jianshu.com/p/927ca066120b 1、定义 Fragment 表示 FragmentActivity 中的行为或界面的一部分。 2、Fragment优点: 与Activi...

笨鸟的专栏 1131

Android知识笔记:记录一个至今仍有很多人写错的技术点,避免入坑!

小编这些年深知大多数初中级Android工程师,想要提升自己,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。因此我收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!资料⬅专栏获取。

2401_85729503的博客 494

FragmentPagerAdapter使用

单独使用Fragment经常会遇到一些问题,比如Fragment切换时,显示和隐藏的Fragment有时候会出现重叠,导致相互之间的UI和事件混乱。 结合ViewPager的使用,则可以避免掉大部分的问题。Google基于PagerAdapter添加了FragmentPagerAdapter类来解决Fragment与ViewPager之间的配合问题。 FragmentPagerAdap

qq_33682144的博客 644
上一篇: 策略模式 - Android.TabHost
下一篇: Android知识体系图
氢电公敌
博客等级 码龄11年 3粉丝 16原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值