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 复用学习相关推荐

  1. 安卓控件 listView 的学习及优化 (ConvetView、viewHolder)

    一. listView 的学习 众所周知ListView 是一个控件,一个在垂直滚动的列表中显示条目的一个控件. 使用方法为: 1. 布局添加Listview 2. 在对应的activity找到lis ...

  2. React学习:路由定义及传参、数据复用-学习笔记

    文章目录 React学习:路由定义及传参.数据复用-学习笔记 在React中使用react-router-dom路由 简单例子 路由定义及传参 React学习:路由定义及传参.数据复用-学习笔记 在R ...

  3. Android之ListView原理学习与优化总结

    在整理前几篇文章的时候有朋友提出写一下ListView的性能优化方面的东西,这个问题也是小马在面试过程中被别人问到的-..今天小马就借此机会来整理下,网上类似的资料蛮多的,倒不如自己写一篇,记录在这个 ...

  4. listview复用机制研究

    Listview在第一次的时候会先把屏幕上绘制的item都new出来,为了讲解方便我把new出来的item都用红色背景,复用的则用绿色背景. 可以看到这个list种有三种item.在第一次展示的时候, ...

  5. Kotlin学习之ListView

    Kotlin学习之ListView Kotlin学习之ListView 前言 一.创建xml 二.创建ListView的adapter 三.在mainactivity中设置listview的adapt ...

  6. Android 开发之漫漫长途 XIV——ListView

    关注 code小生 ,每日一篇技术推送! 作者:忘了12138 地址:http://www.cnblogs.com/wangle12138/p/8441136.html 声明:本文是 忘了12138 ...

  7. android 中自定义安装,Android开发中ListView自定义adapter的封装

    [引入] 我们一般编写listView的时候顺序是这样的: •需要展示的数据集List •为这个数据集编写一个ListView •为这个ListView编写一个Adapter,一般继承自BaseAda ...

  8. 横向ListView(一) ——开篇,基础逻辑实现

    2019独角兽企业重金招聘Python工程师标准>>> 第一次写博文,写得不好的地方还望各位看客见谅 为了学习自定义软件开发,且定制出满足自己需求的控件(不需要将就地使用第三方源码) ...

  9. Android之ListView的getItemViewType和getViewTypeCount

    1.getItemViewType和getViewTypeCount   getItemViewType和getViewTypeCount是ListView中实现复杂列表的两个相关的方法,普通的Lis ...

  10. 对listView的理解

    最简单的listView 用的是ArrayAdapter ,把上下文对象 this item布局,数据源放入adapter中,然后listView布局setAdapter(adapter)就可以展现一 ...

最新文章

  1. 星空主题设计理念_南京婚礼丨一起去看不同经纬度城市的星空吧
  2. Maven项目在pom文件中引入lib下的第三方jar包并打包进去
  3. PHP Mysql-创建数据表
  4. CCF 201312-3 最大的矩形[比较简单]
  5. 编程体系结构(06):Java面向对象
  6. 失去老罗,张一鸣的坚果手机多了什么?
  7. adb命令连接模拟器,could not read ok from ADB Server
  8. Cesium:地球中实现点击浮动弹窗
  9. 商业分析方法与工具总结
  10. 汉王考勤机 二次开发
  11. 这些书你读过一多半,你就是编程大牛!
  12. 致知在格物,物格而后知至,知至而后意诚,意诚而后心正,心正而后身修,身修而后家齐,家齐而后...
  13. c/C++笔试题总结
  14. 关于UVC PTZ功能
  15. 利用python实现微信自动回复群发等操作(不需要登录网页版微信)
  16. 苹果 macbookpro m2 pro、m2 max、m1 pro和 m1 max区别
  17. 【工具介绍】fastcopy的下载与使用方法,可用于硬盘对拷
  18. php tcpdf 嵌入字体,TCPDF如何设置中文字体为内嵌字体?
  19. 如何获取股票的净利润、每股收益、主营营业收入
  20. COBIT4.0简介

热门文章

  1. 大厂的 404 页面都长啥样?看到最后一个,我笑了。。。
  2. Java基础---Java---网络编程---TCP、UDP、UDP-键盘录入方式数据、Socket、TCP复制文件、UDP-聊天
  3. python数据库操作——NoSQL数据库之连接MongoDB、Redis数据库
  4. 启动conda环境_Python入门环境搭建anaconda
  5. matlab设置ylabel,关于ylabel设置的问题
  6. springboot 多线程_从零开始到架构,800页Java+并发+容器+多线程+高并发+Spring+SpringBoot源码...
  7. 算法知识点——(1)特征工程
  8. 奇门对接需求设计_奇门格局详解_-_么学声_张志春
  9. 实现一个本地的json访问地址优化版本--python
  10. 哪个服务器可以玩无限火力,lol无限火力2018开放时间 国服测试服已登录 网友:希望这次不要骗人!...