位置: 编程技术 - 正文

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项目)

  • 公司购买车辆的好处
  • 增值税进项发票当月未开,怎么办
  • 一般纳税人做账流程图
  • 房地产公司自用房屋销售土地增值税计算
  • 增值税技术维护费每年都可以抵减吗?
  • 个体工商户收入怎么核定
  • 小规模纳税人资产负债表和利润表
  • 联营企业子公司抵消比例
  • 支付股权转让费会计科目
  • 一般纳税人增值税怎么做账务处理
  • 合同能源管理项目账务处理
  • 公共租赁住房折旧
  • 未确认融资费用借贷方向
  • 营改增后商品房销售合同印花税的计税依据是什么?
  • 出口企业退税流程
  • 未达起征点纳税申报表怎么填
  • 专票进项税可以抵扣几个月以前的
  • 药企常见税务风险及措施
  • 抵税必须要有发票
  • 帮对方公司垫付违法吗
  • 公司帮员工缴纳个税,不从工资里扣,如何做账
  • 房租发票税金谁承担
  • 员工离职再入职要重新签订合同吗
  • 享受小型微利企业标准
  • 苹果手机录音配音乐怎么配
  • 总分类账是什么的依据
  • 本月未认证的怎么处理
  • 兼职属于劳动关系还是雇佣
  • 技术服务费增值税发票怎么开
  • 财务收入怎么写
  • php处理的图片格式是什么
  • 360pci.exe
  • 其他业务支出包括的内容
  • PHP daddslashes 使用方法介绍
  • 固定资产管理系统多少钱
  • php aes
  • 光下的村庄环境描写
  • 税款入库期是什么意思
  • 代管资金如何做凭证
  • 法人名称是什么意思
  • SQLITE3 使用总结
  • 季度利息收入分录
  • windowsserver2008r2开启远程桌面
  • SQL SERVER 2008 CTE生成结点的FullPath
  • 退还留抵税额政策解读
  • 印花税每月未计提怎么办
  • 小规模开具的1%专票 一般纳税人抵扣
  • 当月发生逾期押金收入12870元
  • 公司增资的法条
  • 应收账款多久收不回来作为坏账
  • 微信提现手续费多少?
  • 股份有限责任公司是什么意思
  • 结转资金和结余资金
  • 固定资产的特点有哪几个
  • 借款利息怎么记账
  • sql server储存过程的创建与使用
  • mysql5.7闪退
  • mysql内存占用一直增高不释放
  • macbookpro 钥匙串
  • mac电脑登录
  • win7系统登录QQ失败提示QQ软件已被破坏或部分文件已经丢失的解决方法
  • win7系统笔记本怎么连接蓝牙耳机
  • win7任务栏还原到下面快捷键
  • Linux VPS中rar、unrar命令安装和使用详解
  • Win10 Mobile Redstone新功能介绍
  • 电子版win10怎么安装
  • shell命令windows
  • win7 64位旗舰版设置插上耳机就能播放声音拔下耳机就自动禁音方法
  • 细说javascript
  • linux tomcat命令
  • jq点击图片让图片进行切换
  • js滚动条怎么调出来
  • unity2d寻路
  • javascript中的document
  • Android调用系统的电话拨号程序
  • Python调用大漠插件
  • 如何理解js的面向对象
  • jquery操作元素样式
  • 国家税务总局广州市税务局
  • 合肥高新公共事务管理有限公司
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设