位置: 编程技术 - 正文

RecycleBin原理解析,带你领会ListView的View重用机制(recyclebinh)

编辑:rootadmin

推荐整理分享RecycleBin原理解析,带你领会ListView的View重用机制(recyclebinh),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:recycled bin,recycled bin,recycle bin,recyclibinhw,recycle/bin,recyclebinghw,recyclebinh,recyclebinwh,内容如对您有帮助,希望把文章链接给更多的朋友!

ListView无疑是Android开发中使用最多的组件之一了,可以肯定是%以上的应用中都是用了ListView,不过ListView也不是万能的,很多时候你会觉得ListView提供给我们的功能并不够,我们需要扩展ListView,或者重新自定义一个支持滚动,view重用特性的组件。如果我们能够了解ListView的内部实现原理,相信对于更好地利用ListView以及对其进行扩展都是不错的。

转载请注明出处: view的重用

ListView最重要的特性就是对view进行了重用,我们只要理解了view的重用原理,就对listview有了很大程度的了解。我们来看看它是如何做的呢?在将这个之前,让我们简要看看ListView的继承结构,ListView继承自AbsListView,而AbsListView继承自AdapterView,AdapterView继承自ViewGroup,因此我们从AdapterView说起就比较明了了。

AdapterView是一个抽象类,里面定义很多接口方法,有待子类去实现,不过也实现了一部分的方法。如下图所示

其中有一部分是继承自ViewGroup的,比如AddView系列以及removeView系列,Accessibility系列。这里我们就不多讲了,相信大家也很熟悉,除此之外就是AdapterView自己的函数,AdapterView顾名思义肯定是根据一个Adapter来生成它内部的view。说到这,我们又不得不引出Adapter这个接口,注意这是个接口,它只是定义了一些接口函数。

这些函数规定了适配器内部每个item的类型,id,每个item对应的view,以及总公的item数量。此外有一个函数需要注意的是hasStableIds(), 这个函数返回一个bool值,如果为true,代表同一个id总是对应同一个item。这个函数在稍后我们将view重用时会用到。AdapterView接口规定了使用Adapter来生成view的函数。

2. RecycheBin

关于view重用的代码大部分都在AbsListView里面,那是因为不光是ListView, 还有GridView也继承了AbsListView,他们都是使用了相同的view重用的原理。我们直接看AbsListView,这个类比较复杂,不过不要担心,我们就从view重用这一点慢慢展开,我们可以看到它有一个内部类叫RecycleBin,正是这个类实现了view的重用,看名字也可以看出。它的成员比较简单,就这些:

mActiveViews代表了在每一次layout开始的时候,位于屏幕上的view, mFirstActivePosition指定了第一个active的view的位置。对于mActiveViews通常的操作为,在每次layout开始,AbsListView会将位于屏幕上的view全部填充到RecycleBin的mActiveViews中去。layout过程中,将下一轮即将显示在屏幕上得view从RecycleBin中取出来,最后如果mActiveViews中还有元素,就在layout结束时将它们统统转移到mScrapView中去。这个流程可以从ListView中的layoutChildren看出,每次layout时,onlayout最终会调用这个函数

从layout的过程就可以看出来,scrapview实际上是一个存放备用view的回收池,每次layout完,有多余的view会存储到池子里,以后可能会用到。那这是layout时候做的事情,如果是scroll的情况呢,情况其实类似。我们来看看scroll的流程图

RecycleBin原理解析,带你领会ListView的View重用机制(recyclebinh)

scroll事件从onTouchEvent函数发起,大家肯定知道的,中间经过一些判断,最终带着deltaY和incrementalDetalY到达trackMotionScroll函数,我们的分析从这个函数开始.

从我的注释,大家可以看到在滚动过程中,RecycleBin所起的作用,当然函数在走到fillGap前,只是完成了一部分滚出view的回收,接下来,是利用这些view进行重用还是生成新的view就要看fillGap函数所做的操作了。

fillGap的实现在ListView中,它只是做了个分派操作,内部分向上滚动和向下滚动分别调用fillUp和fillDown,我们分析其中一个就好

fillDown的两个参数分别为即将开始填充的view的item 位置 和 top坐标位置。

makeAndAddView所做的操作就是获得一个view并将其添加到viewHierarchy上。

makeAndAddView在数据没有改变的情况下,会首先尝试从mActiveViews中去获取。不过需要注意的是,在scroll操作中,我们一开始并没有把屏幕上的view填充到mActiveViews中,因此scroll逻辑走到这里的时候,从mActiveViews中是拿不到view的,为什么还有这一段呢?那是因为这段代码在layout时也会调用的,从layoutChildren函数的重新填充子view那一步中,会调用一系列以fill开头的函数,最终这些函数都会走到这里。现在我们将注意力集中到obtainView上去。

3. Transient State

说到这里读者肯定回问什么是TransientState的View,大家可以看到View类中其实有两个方法,一个叫做hasTransientState,一个叫setHasTransientState,如果一个view被设置了具有transient state,那么系统会尽量保持view的状态属性,不让其它被其他数据模型绑定,比如这个view正在执行动画操作,或者这个view正在跟踪用户的选择。比如我们正在对某个view执行动画操作时,我们可以设定setHasTransientView(true),动画结束后,再设定setHasTransientView(false),注意这两个必须成对出现. 将view设成transient state的其实是对view的一个保护,不让其被其填充新的数据。

RecycleBin对这种状态的view做了单独的处理,其内部有两个SparseArray,用来存储已经滚出屏幕但是设置了transient state状态的view。

两者的区别在于,前者可以通过item的位置找到view,后者通过item的id,找到view。 在前面的分析中,我们可以看到,每次scroll开始时,都会对滚出的屏幕的view调用addScrapView。其实在addScrap过程中,会优先考虑是否添加到这两个容器里面。

在scrapActiveViews函数中也有类似的操作。如果每个view都被设成了transient state,那么scrapView中将不会收到任何view,以至于每次都要重新生成新的view,也就是adapter的getView函数传来的convertView为null,这是因为所有滚出屏幕的view都被添加到transientViews中去了。大家可以试试在adapter的getview函数中,view返回前将其设置为transientState的,那每次我们都需要用inflater去inflate,或者new出新的view。

值得注意的是,只有在view被放入mCurrentScrap或mScrapViews中时,才会去调用onMoveToScrapHeap通知回收监听器,当前view已经被回收,是时候释放一些view所持有的资源了,比如释放图片。

4. SkippedScrap

最后,RecycleBin中还有一个不太重要的mSkippedScrap,什么时候添加view到其中呢?简单搜一下,只有一处,就是在addScrapView函数中,当当前view有transient state,但是却不满足stableId或者 mAdapter数据没有发生变化这两个条件, 这个view就会被添加到skippedScrap中,因为这个view,不能被回收,却又找不到对应的数据item。RecycleBin还有一个函数removeSkippedScrap

在trackMotionScroll,和layoutChildren中会去调用这段代码,很好理解,因为只有在滚动时重新layout时,才会view可能被加入skippedScrap中去。

好了,到了这里RecycleBin大部分的原理都讲得差不多了,其实看透了就很简单。大家在写类似view回收池时可以参考RecycleBin的写法哦。谢谢大家的阅读!

Go项目(二)、toolbar和Material Design风格的选择 一、问题的出现:使用google文档的写法,使用的materialdesign风格只能在androidL上面显示,sdk版本低于的模拟器出现崩溃,所以为了能够在低版本的手机

Android学习 各大网络请求库的比较 转载自:

android Intent的常用参数解说 1Intent.ACTION_MAINString:android.intent.action.MAIN标识Activity为一个程序的开始。比较常用。Input:nothingOutput:nothingactivityandroid:name=.Mainandroid:label=@string/app_nameintent-fi

标签: recyclebinh

本文链接地址:https://www.jiuchutong.com/biancheng/379705.html 转载请保留说明!

上一篇:android 内存使用总结(android内存使用情况)

下一篇:Go项目(二)、toolbar和Material Design风格的选择(gin项目)

  • 关联交易纳税调整期限
  • 4s店代办保险回扣
  • 个税系统设置在哪里
  • 住宿发票税点为什么有6%和3%的区别
  • 替票怎么控制数量
  • 房地产开发精装房是国家规定吗
  • 经营结余年末结转
  • 应交税金及附加包括哪些
  • 佣金支出和手续费税前扣除相关政策依据及会计处理
  • 存货卖出亏损会怎么样
  • 出口货物的进项发票什么时候认证
  • 其他业务收入记账凭证怎么写
  • 发票已缴销什么意思
  • 评估增值的差额是什么
  • 企业员工报销法律规定
  • 工资低于3000要申报吗
  • 营改增行业注释
  • 开发票税收分类编码怎么选
  • 苗木增值税发票税率
  • 减免附加税的账户有哪些
  • 用于非增值税应交税费
  • 公司支付媒体广告费用必须签订合同吗?如果没有签订合同是否不能税前扣除?
  • 两个公司领工资会不会合并纳税
  • 在线上网测试
  • 经营性支出包括哪些
  • 行政事业单位职工体检依据
  • 怎么获得win10纯净版
  • win10电源已接通未充电怎么办
  • 如何更改windows11管理员账户名称
  • 某建筑公司因施工期紧迫,事先未能与有关
  • php验证码扭曲效果怎么做
  • 阿尔比恩洞的级别
  • 可视化大屏的几种模式
  • centos 安装php
  • php中foreach循环遍历数组
  • adan算法
  • css选择器权重
  • php rtrim
  • 出口免税和退税的区别
  • 未签订劳动合同辞退赔偿金怎么算
  • 营改增后材料价差调整
  • 《中华人民共和国治安管理处罚法》
  • 初次购买金税盘怎么做账
  • 企业所得税汇算清缴操作流程
  • 施工项目部主要职责
  • 职工工资如何计算天数
  • 分期收款销售的会计与纳税处理
  • 进项税额转出最终应转到哪里
  • 政府补助收入是指县级以上工会收到的
  • 小规模红冲发票收入正数税额负数
  • 税收会计采用什么记账法
  • win8系统安装软件在桌面找不到
  • WinXP系统VPN连接经常性自动断开的4个解决方法
  • centos.repo
  • windows8文件夹怎么加密
  • win8应用商店打开很慢怎么办
  • centos文件权限详解
  • linux 禁用root
  • mac如何修改用户名称
  • win7开始菜单在哪里
  • window10突然激活失效
  • windows升级后照片不见了
  • win8突然没有声音
  • win7声音扬声器设置
  • win7累计更新补丁包
  • linux调整桌面分辨率
  • linux如何管理文件
  • win8双系统怎么删除一个
  • 安卓应用程序数据
  • javascript获取数据
  • app录音功能开发
  • c#委托的理解
  • js怎么理解
  • Python中list初始化方法示例
  • jquery22
  • 全国税务查询
  • 网上跨区预缴
  • 垠坤集团是属于国企吗
  • 税务局人员调动
  • 国地税账号密码
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

    网站地图: 企业信息 工商信息 财税知识 网络常识 编程技术

    友情链接: 武汉网站建设