ListView 复用学习
2019独角兽企业重金招聘Python工程师标准>>>
1.listview的测量说明
//宽度测量逻辑
if (widthMode == MeasureSpec.UNSPECIFIED) {widthSize = mListPadding.left + mListPadding.right + childWidth +getVerticalScrollbarWidth();
} else {
//初始化childState = combineMeasuredStates(childState, child.getMeasuredState())widthSize |= (childState & MEASURED_STATE_MASK);
}
//高度测量逻辑,这里如果测量模式为UNSPECIFIED,listview的高度就只会显示一个childHeight的高度
if (heightMode == MeasureSpec.UNSPECIFIED) {
//初始化 childHeight = child.getMeasuredHeight();heightSize = mListPadding.top + mListPadding.bottom + childHeight +getVerticalFadingEdgeLength() * 2;
}
//正常情况下测量模式应该是AT_MOST,此时会去累加每一个children的高度
if (heightMode == MeasureSpec.AT_MOST) {heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1);
}
2.listview的复用原理
listview通过RecycleBin进行view的复用.复用的时机在layoutChildren中进行
2.1 RecycleBin原理
RecycleBin两个比较重要的view数组
//存储当前显示的view内容private View[] mActiveViews = new View[0];//根据不同的type废弃的viewlistprivate ArrayList<View>[] mScrapViews;
在listview的layoutChildren()方法中 RecycleBin初始化mActiveViews方式
if (dataChanged) {for (int i = 0; i < childCount; i++) {//数据改变后把view放置废弃的复用池里recycleBin.addScrapView(getChildAt(i), firstPosition+i);}
} else {
//childCount为有效显示的child数量recycleBin.fillActiveViews(childCount, firstPosition);
}...//将目前所有的ActiveViews降级为ScrapViews,并将之前的所有ScrapViews清除,为新产生的
//ActiveViews做好准备
recycleBin.scrapActiveViews();
RecycleBin复用过程 :
与用户进行交互的View,那么这些View会通过RecycleBin直接存储到mActivityView数组当中,以便为了直接复用. 当我们滑动ListView的时候,有些View被滑动到屏幕之外(offScreen) View,那么这些View就成为了ScrapView,也就是废弃的View,已经无法与用户进行交互了,这样在UI视图改变的时候就没有绘制这些无用视图的必要了。他将会被RecycleBin存储到mScrapView数组当中,但是没有被销毁掉,目的是为了二次复用,也就是间接复用。当新的View需要显示的时候,先判断mActivityView中是否存在,如果存在那么我们就可以从mActivityView数组当中直接取出复用,也就是直接复用,否则的话从mScrapView数组当中进行判断,如果存在,那么二次复用当前的视图,如果不存在,那么就需要inflate View了。
搬挪自网络的总结图片:
获取view时复用的代码逻辑如下:
private View fillDown(int pos, int nextTop) {View selectedView = null;int end = (mBottom - mTop);if ((mGroupFlags & CLIP_TO_PADDING_MASK) == CLIP_TO_PADDING_MASK) {end -= mListPadding.bottom;}while (nextTop < end && pos < mItemCount) {// is this the selected item?boolean selected = pos == mSelectedPosition;//获取复用的view逻辑方法View child = makeAndAddView(pos, nextTop, true, mListPadding.left, selected);nextTop = child.getBottom() + mDividerHeight;if (selected) {selectedView = child;}pos++;}setVisibleRangeHint(mFirstPosition, mFirstPosition + getChildCount() - 1);return selectedView;
}
private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,boolean selected) {
if (!mDataChanged) {//获取ActiveView逻辑// Try to use an existing view for this position.final View activeView = mRecycler.getActiveView(position);if (activeView != null) {// Found it. We're reusing an existing child, so it just needs// to be positioned like a scrap view.setupChild(activeView, position, y, flow, childrenLeft, selected, true);return activeView;}}// Make a new view for this position, or convert an unused view if// possible.
/** *如果mActivityView[]数组中没有可用的View,那么尝试从mScrapView数组中读取.然后重新布局. *如果可以从mScrapView数组中可以获取到,那么直接返回调用mAdapter.getView(position,scrapView,this); *如果获取不到那么执行mAdapter.getView(position,null,this)方法. */final View child = obtainView(position, mIsScrap);// This needs to be positioned and measured.setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);return child;
}
这里可以看到如果数据源没有变化的时候,会从mActivityView数组中判断是否存在可以直接复用的View,可能很多读者都不太明白直接复用到底是怎么个过程,举个例子,比如说我们ListView一页可以显示10条数据,那么我们在这个时候滑动一个Item的距离,也就是说把position = 0的Item移除屏幕,将position = 10 的Item移入屏幕,那么position = 1的Item是不是就直接能够从mActivityView数组中拿到呢?这是可以的,我们在第一次加载Item数据的时候,已经将position = 0~9的Item加入到了mActivityView数组当中,那么在第二次加载的时候,由于position = 1 的Item还是ActivityView,那么这里就可以直接从数组中获取,然后重新布局。这里也就表示的是Item的直接复用。
如果我们在mActivityView数组中获取不到position对应的View,那么就尝试从mScrapView废弃View数组中尝试去获取,还拿刚才的例子来说当position = 0的Item被移除屏幕的时候,首先会Detach让View和视图进行分离,清空children,然后将废弃View添加到mScrapView数组当中,当加载position = 10的Item时,mActivityView数组肯定是没有的,也就无法获取到,同样mScrapView中也是不存在postion = 10与之对应的废弃View,说白了就是mScrapView数组只有mScrapView[0]这一项数据,肯定是没有mScrapView[10]这项数据的,那么我们就会这样想,肯定是从Adapter中的getView方法获取新的数据喽,其实并不是这样,虽然mScrapView中虽然没有与之对应的废弃View,但是会返回最后一个缓存的View传递给convertview。那么也就是将mScrapView[0]对应的View返回。总体的流程就是这样。
抄自网络图片:
转载于:https://my.oschina.net/u/2370693/blog/1503478
ListView 复用学习相关推荐
- 安卓控件 listView 的学习及优化 (ConvetView、viewHolder)
一. listView 的学习 众所周知ListView 是一个控件,一个在垂直滚动的列表中显示条目的一个控件. 使用方法为: 1. 布局添加Listview 2. 在对应的activity找到lis ...
- React学习:路由定义及传参、数据复用-学习笔记
文章目录 React学习:路由定义及传参.数据复用-学习笔记 在React中使用react-router-dom路由 简单例子 路由定义及传参 React学习:路由定义及传参.数据复用-学习笔记 在R ...
- Android之ListView原理学习与优化总结
在整理前几篇文章的时候有朋友提出写一下ListView的性能优化方面的东西,这个问题也是小马在面试过程中被别人问到的-..今天小马就借此机会来整理下,网上类似的资料蛮多的,倒不如自己写一篇,记录在这个 ...
- listview复用机制研究
Listview在第一次的时候会先把屏幕上绘制的item都new出来,为了讲解方便我把new出来的item都用红色背景,复用的则用绿色背景. 可以看到这个list种有三种item.在第一次展示的时候, ...
- Kotlin学习之ListView
Kotlin学习之ListView Kotlin学习之ListView 前言 一.创建xml 二.创建ListView的adapter 三.在mainactivity中设置listview的adapt ...
- Android 开发之漫漫长途 XIV——ListView
关注 code小生 ,每日一篇技术推送! 作者:忘了12138 地址:http://www.cnblogs.com/wangle12138/p/8441136.html 声明:本文是 忘了12138 ...
- android 中自定义安装,Android开发中ListView自定义adapter的封装
[引入] 我们一般编写listView的时候顺序是这样的: •需要展示的数据集List •为这个数据集编写一个ListView •为这个ListView编写一个Adapter,一般继承自BaseAda ...
- 横向ListView(一) ——开篇,基础逻辑实现
2019独角兽企业重金招聘Python工程师标准>>> 第一次写博文,写得不好的地方还望各位看客见谅 为了学习自定义软件开发,且定制出满足自己需求的控件(不需要将就地使用第三方源码) ...
- Android之ListView的getItemViewType和getViewTypeCount
1.getItemViewType和getViewTypeCount getItemViewType和getViewTypeCount是ListView中实现复杂列表的两个相关的方法,普通的Lis ...
- 对listView的理解
最简单的listView 用的是ArrayAdapter ,把上下文对象 this item布局,数据源放入adapter中,然后listView布局setAdapter(adapter)就可以展现一 ...
最新文章
- 星空主题设计理念_南京婚礼丨一起去看不同经纬度城市的星空吧
- Maven项目在pom文件中引入lib下的第三方jar包并打包进去
- PHP Mysql-创建数据表
- CCF 201312-3 最大的矩形[比较简单]
- 编程体系结构(06):Java面向对象
- 失去老罗,张一鸣的坚果手机多了什么?
- adb命令连接模拟器,could not read ok from ADB Server
- Cesium:地球中实现点击浮动弹窗
- 商业分析方法与工具总结
- 汉王考勤机 二次开发
- 这些书你读过一多半,你就是编程大牛!
- 致知在格物,物格而后知至,知至而后意诚,意诚而后心正,心正而后身修,身修而后家齐,家齐而后...
- c/C++笔试题总结
- 关于UVC PTZ功能
- 利用python实现微信自动回复群发等操作(不需要登录网页版微信)
- 苹果 macbookpro m2 pro、m2 max、m1 pro和 m1 max区别
- 【工具介绍】fastcopy的下载与使用方法,可用于硬盘对拷
- php tcpdf 嵌入字体,TCPDF如何设置中文字体为内嵌字体?
- 如何获取股票的净利润、每股收益、主营营业收入
- COBIT4.0简介
热门文章
- 大厂的 404 页面都长啥样?看到最后一个,我笑了。。。
- Java基础---Java---网络编程---TCP、UDP、UDP-键盘录入方式数据、Socket、TCP复制文件、UDP-聊天
- python数据库操作——NoSQL数据库之连接MongoDB、Redis数据库
- 启动conda环境_Python入门环境搭建anaconda
- matlab设置ylabel,关于ylabel设置的问题
- springboot 多线程_从零开始到架构,800页Java+并发+容器+多线程+高并发+Spring+SpringBoot源码...
- 算法知识点——(1)特征工程
- 奇门对接需求设计_奇门格局详解_-_么学声_张志春
- 实现一个本地的json访问地址优化版本--python
- 哪个服务器可以玩无限火力,lol无限火力2018开放时间 国服测试服已登录 网友:希望这次不要骗人!...