FragmentStatePagerAdapter的危险_智域智联科技的博客-程序员秘密

技术标签: 安卓教程  

许多Android开发人员感到困惑,甚至都不知道FragmentPagerAdapterFragmentStatePagerAdapter之间的区别。也越来越notifyDatasetChanged()对工作可能是令人沮丧的时候。使用这些适配器很容易发生内存泄漏。我将从这些基础知识开始,然后更深入地介绍实现细节,并指出一些鲜为人知的陷阱(您是否知道FragmentPagerAdapter中的Fragment仅在完成Activity后才从内存中释放出来,请继续阅读:-))。

基本区别

FragmentPagerAdapter

适用于有限数量(固定)的项目(片段)。为什么?因为一旦创建,它将永远不会从FragmentManager中删除片段实例(除非Activity完成)。它仅将视图与当前不可见的片段分离。一旦无法到达您的片段,就会在片段上调用它,稍后返回该片段时,就会调用它。onDestroyView()onCreateView()

FragmentStatePagerAdapter

精明的。删除一旦你返回到现有项目片段实例重建和状态恢复此适配器适用于一个未知的数量或在项目发生很大的变化列表清单。

FragmentPagerAdapter —内存泄漏危险

FragmentPagerAdapter中的片段仅被分离,并且永远不会从FragmentManager中移除(除非活动完成)。使用FragmentPagerAdapter时,必须确保清除中对当前View或Context的所有引用onDestroyView()。否则,垃圾收集器将无法释放整个视图,甚至无法释放活动。这意味着将任何与“视图/上下文”相关的字段设置为null(Butterknife可以自动将其取消绑定),并删除所有可能泄漏“上下文”或“视图”的侦听器。

否则,可能会耗尽内存-假设FragmentPagerAdapter中有10个项目。滑动所有这些视图将在内存中保留10个视图,而不是仅保留最后三个视图(取决于setOffScreenPageLimit()设置),旋转屏幕会使其更糟(十分之七)仍将保留对“被破坏”活动的引用。

僵尸分离碎片

您还需要考虑以下问题:片段永远不会从FragmentManager中删除。内存中可能有数百个分离的实例,这是因为您要不断更改适配器绑定到的一小部分项目。它将创建新项目并保留旧的分离片段。

FragmentStatePagerAdapter的问题不大,因为它正在从FragmentManager中删除整个Fragment实例。如果您滑动许多片段,可能会遇到麻烦,并且由于每个片段都会在地图中添加一个新的Bundle实例,因此它可能会变得很大(可能会导致TransactionTooLargeException方向更改)。

带有notifyDatasetChanged()的问题

我猜我们每个人在调用notifyDatasetChanged()这些适配器之一时都会遇到问题。这样做不会刷新当前可见的片段,而您必须“来回滑动”以强制适配器重新创建当前片段。这两个PagerAdapters都在缓存和重用Fragment实例,这很好,因为否则调用notifyDataSetChanged会再次重新创建它们(即使不是必需的)。

同样非常重要的一点是,notifyDataSetChanged()适用于数据集更改的情况,这意味着是否删除或添加了某些项目。notifyDatasetChanged()方法并不用于刷新当前显示的片段或其视图。如果您希望某些数据发生更改时刷新它们的视图,则需要在Fragment中添加一些侦听器/回调。

FragmentPagerAdapter和notifyDatasetChanged()

您需要在FragmentPagerAdapter中重写两个方法以支持数据集更改。

int getItemPosition(Object object)

在宿主视图试图确定项目位置是否已更改时调用。返回POSITION_UNCHANGED如果给定项目的立场没有改变,或者POSITION_NONE如果该项目是在适配器不再存在。

默认实现假定项目永远不会改变位置并且总是返回POSITION_UNCHANGED

您需要getItemPosition(Object object)使用某种逻辑来实现,该逻辑确定当前片段在数据集中的位置(例如,迭代数据集并搜索与片段相对应的入口位置)。

始终返回POSITION_NONE会导致内存和性能低下-即使它们在数据集中的位置未更改,也会始终分离当前可见的片段并重新创建它们。并且旧的片段将保留在内存中,直到您离开活动。

long getItemId(int position)

将在给定位置返回该商品的唯一标识符。默认实现返回给定位置。如果项的位置可以更改,则子类应重写此方法。

在内部使用此方法在instantiateItem()FragmentManager中搜索现有的分离Fragment实例。调用notifyDataSetChanged()而不覆盖此方法将只返回当前索引上的现有Fragment实例。您需要返回该片段的唯一标识符

FragmentStatePagerAdapter —状态包“错误”

您只需要重写getItemPosition()即可支持FragmentStatePagerAdapter中的数据集更改(此处没有getItemId()方法)。与FragmentPagerAdapter所提到的一样,这里也有同样的事情(不一定总是返回POSITION_NONE)。

这里有一个陷阱-相当不愉快... 此博客中详细描述了该问题。问题在于FragmentStatePagerAdapter保持状态捆绑的ArrayList。如果该instantiateItem()方法不存在,方法将创建一个新的Fragment实例-但是它将查找ArrayList并根据项目索引选择Bundle!这可以是属于该索引上一个先前(不同)Fragment实例的Bundle。如果要更改数据集并更新适配器,则可以执行此操作。阅读链接的博客以获取一些可能的解决方案。

片段{}当前不在FragmentManager中

这个问题已经公开,并且四年以上没有修复!此博客对此进行了详细描述。这确实令人沮丧,在这之后,您可能会考虑拥有自己的“固定”版本的FragmentStatePagerAdapter。(编辑:我们正在研究它-将在 https://github.com/inloop/UpdatableFragmentStatePagerAdapter上提供)。

FragmentStatePagerAdapter完全早于PagerAdapters的数据集更改功能。如果您有一个需要处理数据集更改的PagerAdapter,那么与从FragmentStatePagerAdapter开始相比,直接从PagerAdapter实现合同可能会更容易。

好吧……很好,但是应该对此有一些大的警告。一个简单的解决方法是始终返回POSITION_NONE getItemPosition()。但这会带来性能上的损失。

还有PagerAdapter…

也许我应该在一开始就说过这一点-但是请记住,如果您的应用程序中有ViewPager,则不必总是使用Fragments。如果您使用一些复合的View布局和一个简单的PagerAdapter,则完全没有问题,而且也很简单。这取决于您是否需要所有生命周期回调。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_27809865/article/details/105044919

智能推荐

频繁项集挖掘算法在告警关联中的应用_云智慧AIOps社区的博客-程序员秘密_频繁项挖掘

# 技术黑板报 # 第十期推荐阅读时长:15min在上一篇技术黑板报中,我们介绍了频繁项集挖掘这一问题,并讲解了Apriori算法与FP-Growth算法的技术原理。本期技术黑板报我们将主要围绕频繁项集挖掘算法的实际应用,即当该算法应用到告警关联场景中时,我们遇到了哪些问题,如何解决这些问题,以及我们如何在原始FP-Growth算法的基础上进行改进,从而研发了专用于告警关联场景下的CW-FP-Growth算法。为了展示该算法的实际效果,我们在文末给出了这一算法在脱敏数据中的案例。..

AlertManager实现webhook告警(使用Postman测试)_程序员小王java的博客-程序员秘密_alertmanage webhook

AlertManager实现webhook告警(使用Postman测试),Alertmanager 主要用于接收 Prometheus 发送的告警信息,它支持丰富的告警通知渠道,而且很容易做到告警信息进行去重,降噪,分组等,是一款前卫的告警通知系统。但是我们公司内部不使用Prometheus,只使用AlertManager.

Java基础__Java中异常处理那些事_weixin_30414635的博客-程序员秘密

一、Exception 类的层次所有的异常类是从 java.lang.Exception 类继承的子类。Exception 类是 Throwable 类的子类。除了Exception类外,Throwable还有一个子类Error 。Error 用来指示运行时环境发生的错误。异常类有两个主要的子类:IOException 类和 RuntimeException 类。...

百度地图离线开发demo(初始化地图)_oliver666666的博客-程序员秘密_百度地图初始化

使用百度地图api,只要瓦片对应上,api对上了,地图的使用还是较为简单的,demo官网上的也可参考,只需将BMapGL后边的gl去掉即可<!--地图初始化 --><template> <div id="allmap" style="width: 100%;height: 100%;" /></template><script>export default { components: {}..

opencv和HALCON坐标系的不同_冯相文要加油呀的博客-程序员秘密

opencv的坐标原点在左上角,往右为X轴正方向,往下为Y轴正方向(用Image Watch可以很容易看出来)HALCON的坐标原点在左上角,往右为Y轴正方向,往下为X轴正方向(HALCON窗口左下角可以出来)

随便推点

聚播微信群控云控引擎二次开发SDK服务端对接接口_虫小宝的博客-程序员秘密

聚播微信群控云控引擎二次开发SDK服务端对接接口 case HeartBeatReq: {// 客户端发送的心跳包 heartBeatReqHandler.handleMsg(ctx, msgVo); break; } case DeviceAuthReq: {// 设备客户端授权 设备(手机客户端、客服客户端)获取通信token请求 ...

C++ 哈希表_ZS_Wang_Blogs的博客-程序员秘密_c++ 哈希表

什么是哈希表map、hash_map、unordered_map的引入unordered_map的用法1. 什么是哈希表1.1 哈希表的定义“散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。从上面的百度百科,我们小白可以知道3点:哈希表也叫散列表哈希表是一个数据结构散列表是数组.

计算机网考 总结范文,年终工作总结范文_2017考研:计算机网络复习核心_沪江英语..._Wingdows的博客-程序员秘密

计算机专业是考研报考的热门专业之一,但是计算机考研要复习很多的专业课,复习起来也很费时间。今天就和大家分享计算机网络这门课的复习重点。1、计算机网络体系结构这部分内容要了解计算机网络概念的概念、组成;计算机网络的分类,发展过程等。理解网络分层结构、网络协议、接口、服务等概念。重点掌握OSI参考模型和TCP/IP模型的区别和联系。2、物理层对这部分内容的考查,以基本原理和概念的形式为主。掌握信道、信...

python cnn 回归模型_CNN学习笔记:线性回归_三川啦啦啦的博客-程序员秘密

CNN学习笔记:Logistic回归线性回归二分类问题Logistic回归是一个用于二分分类的算法,比如我们有一张图片,判断其是否为一张猫图,为猫输出1,否则输出0。基本术语进行机器学习,首先要有数据,比如我们收集了一批关于西瓜的数据,例如(色泽=青绿;根蒂=收缩;敲声=浊响)(色泽=乌黑;根蒂=稍蜷;敲声=沉闷)(色泽=浅白;根蒂=硬挺;敲声=清脆)每对括号内是一条记录,这组记录的集合称为一个数...

网页JS方法中动态加载文件_weixin_34387284的博客-程序员秘密

为什么80%的码农都做不了架构师?>>> ...

PCL学习笔记(一)_weixin_33857230的博客-程序员秘密

由于项目需要,开始学习一下HP公司的PCL打印语言,发现这方面的中文资料非常少,我做下记录也为后人提供便利。关于PCL的介绍可以参考wiki百科http://zh.wikipedia.org/zh-cn/PCL相关文档也可以在此链接下载。我参考的是PCL 5E technical reference manual 主要做一下翻译工作。。。一、概述PCL ,是Printer Comm...

推荐文章

热门文章

相关标签