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. ios - Push远程通知代码设置 DeviceToken
  2. node.js+express,实现RESTful API
  3. S/4HANA服务订单Service Order的批量创建
  4. 洛谷 P1404 平均数
  5. chrome的timeline的问题?
  6. Java学习日志(四)
  7. PHP网站首页空白刷新就好了,部署好后网站一片空白,不显示内容
  8. 常见的遍历数组和对象的方法
  9. 树莓派_配置交叉编译环境
  10. Windows下SVN已检出项目自动更新
  11. MATLAB计算不定积分与定积分
  12. MAC安装maven步骤
  13. 5.9 Illustrator颜色的设置 [Illustrator CC教程]
  14. 15.2. switchport trunk encapsulation dot1q 提示 invaild input at^marker.
  15. ode45的常用和扩展用法
  16. solidworks2014方程式添加全局变量存在句法错误的解决方案
  17. 知识图谱架构(Knowledge Graph)
  18. 九招使用 Telegram必学,使用Telegram 必看实用功能
  19. 入网许可证_进网许可证、电信设备入网许可证详解!
  20. 「镁客·请讲」太平洋未来科技李建亿:深耕AR技术,布局垂直领域

热门文章

  1. 如何优化你的布局层级结构之RelativeLayout和LinearLayout及FrameLayout性能分析
  2. bat 暂停一段时间_BAT面试问是否具备3年工作经验,这么回答绝了!
  3. springboot mybatis如何打印出查询语句_Java 面试,如何坐等 offer?
  4. Python 爬取电影街美剧网址
  5. C语言求组合数取模,C 习题1.pdf
  6. python自定义标识符_《Python 3程序开发指南(第2版•修订版)》——第2章 数据类型 2.1 标识符与关键字...
  7. .net 怎么使用github_超快组装软件的使用hifiasm软件
  8. mysql日志模式默认是raw还是_深入学习MySQL 02 日志系统:bin log,redo log,undo log
  9. 刷题进阶 -- 剑指Offer、力扣算法题
  10. 安装Firefly错误-Unable to find vcvarsall.bat