位置: 编程技术 - 正文

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

  • 小规模纳税人能开专票吗
  • 增值税发票抵扣操作流程
  • 车票增值税抵扣如何申报
  • 出口货物丢失起诉谁
  • 以前年度损益调整结转到未分配利润
  • 建设工程劳务分包的规定
  • 待处理财产损益年底怎么处理
  • 政府奖励收入要交企业所得税么
  • 公司开办期间的装修费怎么会计处理
  • 利润表没有资产减值损失这一栏,需要增加吗
  • 丢失发票联和抵扣联
  • 保证金抵扣货款分录
  • 房地产销售土地增值税纳税人减免申请核准表
  • 传媒公司发传单
  • 什么情况下是应收账款
  • 税控设备全额抵扣政策
  • 行政单位基建账统一核算
  • 如何异地缴纳个人医保
  • 税种案例分析
  • 发票作废相关规定
  • 附加税税率计税依据
  • 母公司向全资子公司增资
  • 以后年度继续扣除广告宣传费,要怎么写分录?
  • 税务机关核定征收契税
  • 跨区经营的税务政策
  • 收到联营企业分派的现金股利为什么不计入利润总额
  • 没发票大额费用支出能税前扣除吗?
  • 购置税和购车税一样吗
  • 企业收到政府拆迁补偿款要交税吗怎么做账
  • mac菜单栏设置在哪里
  • macOS 11.0.1(20B29)更新了什么?macOS Big Sur 11.0.1(20B29)更新详解
  • 各部门领料情况,a产品耗用甲材料3200元
  • 增值税进项税已勾选没确认能自动生成吗
  • 所得税季度预缴怎么算
  • 完美解决索尼电视arc无声音
  • php提高性能
  • 何为租赁合同
  • iframe内嵌页面
  • 谷歌浏览器如何设置主页为默认页
  • 海獭妈妈和新生儿的故事
  • 工商银行电子回执单怎么查看
  • js加密解密源代码
  • firewall enable
  • 销售返利的会计处理方法
  • 淘宝企业店必须绑定对公账户吗
  • python分布式执行框架Ray的介绍
  • 交易性金融资产是什么意思
  • 垫付应收款怎么做会计分录
  • 在excel中怎么制作
  • mongodb查询操作
  • 增值税专用发票的税率是多少啊
  • 两个公司发工资公司会发现吗
  • 当月的进项税可以不认证吗?
  • 对方企业倒闭了是否能函证
  • 发票当月没开
  • 怎么才能回到一年前
  • 国有资产如何保值
  • 老板从公司借款怎么处理
  • 建筑施工企业在12个月内第三次发生生产安全事故的
  • 以考核为由扣除工资
  • 拆借 拆放
  • MySQL PXC构建一个新节点只需IST传输的方法(推荐)
  • solaris syslog
  • windowxp操作系统
  • mac的qq缓存在哪里怎么打开
  • win7桌面提示7601
  • win7 手动输入用户名
  • linux系统怎样安装
  • xp注册表文件在哪
  • msoxmled.exe是什么软件
  • 如何查看windows使用痕迹
  • mysqld-nt.exe - mysqld-nt是什么进程 有什么用
  • 批处理文件命令大全
  • unity3drpg游戏教程
  • 酷狗模拟器
  • linux sleep 2
  • android判断应用是否在前台
  • 电子税务局打印发票提示本机未检测到
  • 财税36号文附件3
  • 重庆地税局官网公众号
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设