探究ListView 的缓存机制
概述
ListView 是继承AbListView,AbListView是所有列表类控件的基类。
ListView的数据加载
在ListView数据加载中最关键的一个函数就是makeAndAddView(),这个函数的作用就获得一个ChildView并把该ChildView添加到List中,具体见源码分析:
private View makeAndAddView(int position, int y, boolean flow, int childrenLeft,
boolean selected) {
View child;//即ChildView
//如果数据没有发生改变
if (!mDataChanged) {
//优先从循环器中获取该位置的视图
// Try to use an existing view for this position
child = mRecycler.getActiveView(position);
if (child != null) {
// Found it -- we're using an existing child
//如果找到了就直接添加到List中
// This just needs to be positioned
setupChild(child, position, y, flow, childrenLeft, selected, true);
return child;
}
}
//如果数据发生了改变,则在该位置上新建一个视图,或者如果可能的话转换一个已经没有用的视图(可能是当整个ListView其他位置发生了变化,但是该位置的ChildView并未发生任何变化)
// Make a new view for this position, or convert an unused view if possible
child = obtainView(position, mIsScrap);
// This needs to be positioned and measured
setupChild(child, position, y, flow, childrenLeft, selected, mIsScrap[0]);
//返回该childView
return child;
}
ListView的缓存机制
当ListView发生滑动操作时,若干已经加载的ChildView会被因滑动而被暂时隐藏掉,为了避免下次显示再重新加载,这时ListView的缓存机制就会被触发,即运行layoutChildren()函数(其实任何触碰事件都会触发,即onTouchEvent() -。-)。
那么ListView的缓存机制是依靠什么来缓存的呢?答案就是AbListView中 的内部类RecycleBin。关于RecycleBin的具体作用,源码中的注释已经解释的非常清楚了,在此就不在赘述。
/**
* The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of
* storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the
* start of a layout. By construction, they are displaying current information. At the end of
* layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that
* could potentially be used by the adapter to avoid allocating views unnecessarily.
*... ...
*/
当需要缓存ActiveViews时会调用fillActiveViews()函数,该函数会把ListView中的所有ActiveViews 一次性都缓存起来。
/**
* Fill ActiveViews with all of the children of the AbsListView.
* ... ...
*/
void fillActiveViews(int childCount, int firstActivePosition) {
if (mActiveViews.length < childCount) {
mActiveViews = new View[childCount];
}
mFirstActivePosition = firstActivePosition;
//noinspection MismatchedReadAndWriteOfArray
final View[] activeViews = mActiveViews;
... ...
}
而对于ScrapViews则是调用的addScrapView()函数。
/**
* Puts a view into the list of scrap views.
* <p>
* If the list data hasn't changed or the adapter has stable IDs, views
* with transient state will be preserved for later retrieval.
*
* @param scrap The view to add
* @param position The view's position within its parent
*/
void addScrapView(View scrap, int position) {
... ...
// Don't scrap views that have transient state.
final boolean scrapHasTransientState = scrap.hasTransientState();
if (scrapHasTransientState) {
//Transient状态
... ...
}else{
//scrap状态
... ...
}
... ...
}
该函数中又分为两个不同的level,一个是transient瞬时态,另一个就是一般的普通态,关于这两个状态的区分我个人的想法是为了更加快速的获取ScrapViews,因为处于瞬时状态的view最有可能是接下来将要在界面上显示的View,毕竟你向上或向下滑动列表时目的就是这个,这一点在obtainView()函数中得到了体现:
View obtainView(int position, boolean[] isScrap) {
... ...
//优先获取TransientStateView
scrapView = mRecycler.getTransientStateView(position);
if (scrapView == null) {
scrapView = mRecycler.getScrapView(position);
}
... ...
}
还有一个比较重要的函数就是scrapActiveViews()函数,它的作用是将目前所有的ActiveViews降级为ScrapViews,并将之前的所有ScrapViews清除。该函数在每次调用layoutChildern()函数时必定会被调用执行,目的就是为清空所有当前的ActiveViews,为新产生的ActiveViews做好准备。
/**
* Move all views remaining in mActiveViews to mScrapViews.
*/
void scrapActiveViews() {
... ...
//该函数确保mScrapViews的大小不会超过mActiveViews
pruneScrapViews();
}
结语
以上是阅读了ListView以及AbListView源码后的一些心得总结,毕竟阅读Android源码也才刚刚起步,还有很多地方理解的不是很透彻,上文若有理解不当之处欢迎各位指正。
探究ListView 的缓存机制的更多相关文章
- Android学习——ListView的缓存机制
在使用ListView的时候,需要加载适配器和数据源,这篇文章主要介绍一下ListView的使用以及利用ListView的缓存机制来减少系统的初始化时间. ListView的使用 ListView和V ...
- Android笔记(二十五) ListView的缓存机制与BaseAdapter
之前接触了ListView和Adapter,Adapter将数据源和View连接起来,实际应用中,我们要显示的数据往往有很多,而屏幕只有那么大,系统只能屏幕所能显示的内容,当我们滑动屏幕,会将旧的内容 ...
- Android图片加载框架最全解析(三),深入探究Glide的缓存机制
在本系列的上一篇文章中,我带着大家一起阅读了一遍Glide的源码,初步了解了这个强大的图片加载框架的基本执行流程. 不过,上一篇文章只能说是比较粗略地阅读了Glide整个执行流程方面的源码,搞明白了G ...
- 【腾讯Bugly干货分享】Android ListView与RecyclerView对比浅析--缓存机制
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/5811d3e3ab10c62013697408 作者:黄宁源 一,背景 Recy ...
- RecyclerView与ListView 对比浅析:缓存机制
一. 背景 PS:相关知识:ListView与RecyclerView缓存机制原理大致相似,如下图所示: 滑动过程中,离屏的ItemView即被回收至缓存,入屏的ItemView则会优先从缓存中获取, ...
- ListView与RecyclerView对比浅析——缓存机制
https://www.jianshu.com/p/193fb966e954 一,背景 RecyclerView是谷歌官方出的一个用于大量数据展示的新控件,可以用来代替传统的ListView,更加强大 ...
- RecyclerView 源码分析(二) —— 缓存机制
在前一篇文章 RecyclerView 源码分析(一) -- 绘制流程解析 介绍了 RecyclerView 的绘制流程,RecyclerView 通过将绘制流程从 View 中抽取出来,放到 Lay ...
- 再次探究Android ListView缓存机制
概述 虽然现在5.0后Google推出了RecycleView,但在5.0 Lollipop普及前Listview仍会被广泛使用,所以打算再次探究一下Listview的源码,了解一下Listview ...
- [转]Android ListView 与 RecyclerView 对比浅析—缓存机制
从源码角度剖析ListView 与 RecyclerView 缓存机制的不同 https://zhuanlan.zhihu.com/p/23339185 原文地址:http://dev.qq.com/ ...
随机推荐
- HDOJ(HDU) 2156 分数矩阵(嗯、求和)
Problem Description 我们定义如下矩阵: 1/1 1/2 1/3 1/2 1/1 1/2 1/3 1/2 1/1 矩阵对角线上的元素始终是1/1,对角线两边分数的分母逐个递增. 请求 ...
- bzoj 1070 [SCOI2007]修车(最小费用最大流)
1070: [SCOI2007]修车 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 3515 Solved: 1411[Submit][Status] ...
- 关于Linux
这是一个2B让我写的关于Linux的一点东西. 其实我对Linux一直都是持有一种很尊敬的态度,作为一个非商业性的操作系统,能够成长成这样简直是不可思议,有一种Dota在游戏界的感觉,很让人佩服.但是 ...
- Piggy-Bank(完全背包)
/* http://acm.hdu.edu.cn/showproblem.php?pid=1114 完全背包问题 再判断背包能否装满 题意: 给出存空钱罐的重量以及装满时的重量 给出每种硬币的面值以及 ...
- openfire for mac 无法启动
http://blog.csdn.net/winer888/article/details/49886281 ①:sudo chmod -R 777 /usr/local/openfire/bin ② ...
- Websphere内存溢出的日志
项目中碰到Websphere内存溢出的情况.原因可能:出现过多内存泄漏,或者分配过多大内存等.解决方法:1.进入was管理控制台,选择 应用程序服务器 > server1 > 进程定义 & ...
- redis学习心得之二【redis主从配置】
在前一节我们已经实践启动了一个redis服务,我们将其作为主机,现为其创建一个从机作备份使用 1.复制一份配置出来为从机所用 ~$ cp redis/etc/redis.conf ...
- composer安装第三方库
生成composer.json 首先需要安装composer,composer -v出现如下,则表明安装成功. 编写composer.json { "name": "ww ...
- S3C2440 I2C总线控制
概述:话不多说,直接上图 多主机IIC总线控制(IICCON): IIC控制总线状态(IICSTAT): IIC总线地址(IICADD): IIC发送,接收总线寄存器(IICDS) IIC总线控制寄存 ...
- HeaderViewListAdapter
该类其实就是普通使用的Adapter的一个包装类,就是为了添加header和footer而定义的.该类一般不直接使用,当ListView有header和footer时,ListView中会自动把Ada ...