位置: 编程技术 - 正文

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

  • 增值税发票超过3个月可以作废吗
  • 课税为什么叫课税
  • 退休职工能否扣医保
  • 培训属于什么服务行业
  • 公司购买的打印机
  • 发生销售折让时为什么不冲减成本
  • 增值税专用发票有效期是多长时间
  • 长期借款会计科目编码
  • 丢失发票罚款如何入账
  • 未分配利润借方表示增加还是减少
  • 上月暂估收入本月开票增值税实操
  • 企业转给法人的流程
  • 印花税到底什么通俗一点
  • 一般纳税人上个月没有申报这个月申报不了
  • 有没有薪酬
  • 施工单位临时设施的搭建费属于
  • 取得海运费发票怎么入账
  • 现金流风险分析
  • 以前年度损益调整借贷方向
  • 企业生产过程中的一个安全问题必须
  • 返利冲减收入
  • win11资源管理器怎么打开
  • 2014年最佳阵容
  • 商品房的维修金该怎么交
  • php curl_multi_init
  • windows商店如何切换地区
  • 预提收入的会计处理方法
  • 出售固定资产增值税怎么处理
  • nginx apache php
  • 股东已转让股权还可以追究出资吗
  • 八仙花的养殖方法冬季怎么养
  • 交易性金融资产的账务处理
  • 计算企业所得税分录
  • 借应付职工薪酬贷其他应收款
  • php array_product
  • php数组排列组合算法
  • 出租人经营租赁会计分录
  • 网上购物没有发票怎么保修
  • 工程代建的性质
  • 看望生病职工慰问品
  • 织梦如何采集文章
  • mysql的联合查询
  • 什么是备抵类账户
  • 租赁合同印花税率多少
  • 股东买房能在银行贷款吗
  • 用友u8固定资产减少怎么撤销
  • sql2008r2安装教程
  • SQL Server 2005 同步复制技术
  • 一般纳税人金税盘怎么清卡
  • 一般纳税人适用3%税率情况
  • 预收的房租需要交房产税吗
  • 合理损耗如何处理
  • 公司账户转账给个人要交税吗
  • 民间非营利组织会计制度
  • 收据可不可以做账
  • 小规模纳税人怎么算税
  • mysql如何实现主从复制的具体流程
  • win10如何设置视频缩略图
  • 笔记本摄像头摄像
  • [下载转存] 经验本题库源文件下载转存 秒结
  • 如何配置linux
  • msxct.exe - msxct是什么进程 有什么用
  • win7电脑桌面图标间隔太大怎么调
  • win8系统怎么设置共享局域网
  • 解决的英文
  • windows10移动
  • Unity3D游戏开发(第2版)
  • [置顶] 《诸天星河》
  • eclipse 代码提示指令在哪改
  • android仿qq聊天
  • 重庆国税12366电子税务局官网入口
  • 吉林省地方税务局
  • 智能财税证书含金量多少
  • 云南省国家税务局网上办税服务厅
  • 全国税务系统全面从严治党工作会议2023年
  • 云南国税局官网网站
  • 税务uk数据怎么导出来
  • 建筑公司材料发票
  • 山东地税app
  • 年报汇算清缴怎么做
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号

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

    友情链接: 武汉网站建设