概述

虽然现在5.0后Google推出了RecycleView,但在5.0 Lollipop普及前Listview仍会被广泛使用,所以打算再次探究一下Listview的源码,了解一下Listview 的构成及加载机制。

探究



上图简单梳理了Listview的构成及与其相关类之间的关系,并简要地列出了些重要的方法和内部类。

AdapterView

从上图可以清晰的看出Listview归根究底是继承自AdapterView。AdaterView是一个抽象类,一些最基本和通用方法或接口都是在此定义或声明的,其中一些更是开发者所常用的,诸如:

//Item Click 监听接口
/**
* Interface definition for a callback to be invoked when an item in this
* AdapterView has been clicked.
*/
public interface OnItemClickListener {
... ...
void onItemClick(AdapterView<?> parent, View view, int position, long id);
} //设置Adapter抽象方法
/**
* Sets the adapter that provides the data and the views to represent the data
* in this widget.
*
* @param adapter The adapter to use to create this view's content.
*/
public abstract void setAdapter(T adapter);

此外在AdapterView中实现了DataSetObserver抽象类,我们一般调用mAdapter.notifyChanged()所触发的就是DataSetObserver的onChanged()方法。关键源码如下:

class AdapterDataSetObserver extends DataSetObserver {

    private Parcelable mInstanceState = null;

    @Override
public void onChanged() {
mDataChanged = true;
mOldItemCount = mItemCount;
mItemCount = getAdapter().getCount();
... ...
} @Override
public void onInvalidated() {
mDataChanged = true;
... ...
}
... ...
}

AbsListView

AbsListView是继承自AdapterView,在该类中实现了一个非常重要的内部类RecycleBin,内部类RecycleBin其实就是AbsListView缓存机制的核心类,它的作用是管理AbsListView的item存储和取得。AbsListview的缓存分为两级,第一级为activeView,第二级为scrapview。二者的间的转换主要是在layoutChildren()方法进行(该抽象方法在LisView中实现),具体分析见如下源码:

@Override
protected void layoutChildren() {
... ...
//说明RecycleBin并不缓存HeadView和FooterView
// Don't put header or footer views into the Recycler.
//Those are already cached in mHeaderViews;
if (dataChanged) {
//如果data改变了,则当前所有childView都添加至mScrapViews;
for (int i = 0; i < childCount; i++) {
recycleBin.addScrapView(getChildAt(i), firstPosition+i);
if (ViewDebug.TRACE_RECYCLER) {
ViewDebug.trace(getChildAt(i),
ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP, index, i);
}
}
} else {
//若data未改变,即第一次加载时,根据当前childCount数量对mArchiveViews赋值。
recycleBin.fillActiveViews(childCount, firstPosition);
}
... ...
switch (mLayoutMode) {
... ...(在switch条件中执行makeAndAddView函数)
}
// Flush any cached views that did not get reused above
//执行makeAndAddView函数后将需要显示的item view已添加至ListView中,
//所以跳出siwtch后会将缓存的mActiveViews全部转换为mScrapViews。
recycleBin.scrapActiveViews();
... ...
}

同时AbsListview中定义了一个ObtainView方法,一般地当Listview加载时若发现没有可复用的itemView时要么从RecycleBin中转换ScrapView,要么是通过mAdapter.getView()获取新的itemView,ObtainView方法就是专门用来处理上述的两种情况,具体分析如下:

View obtainView(int position, boolean[] isScrap) {
... ...
scrapView = mRecycler.getScrapView(position);
View child;
//若scrapView不为空,则将scrapView转换为可复用的itemView
if (scrapView != null) {
... ...
child = mAdapter.getView(position, scrapView, this);
... ...
}else{
//若scrapView为空,则通过adapter.getView()函数获取新的ItemView
child = mAdapter.getView(position, null, this);
... ...
}
}

结语

OK,今天就先总结这么多了,不足之处欢迎指出。当然今后使用RecycleView会是一种趋势,和AS一样,找机会要研究一下。

作者:XycZero

查看原文:http://www.xyczero.com/blog/article/18/.

再次探究Android ListView缓存机制的更多相关文章

  1. ListView缓存机制踩过的坑

    ListView,GrildView使用时候经常会用到缓存机制,随意一搜,例子成千上万,但是讲解都是很一致,跟自己踩的坑很少有人讲解到. 测试 需求: GrildView 分三列显示,默认背景为白色, ...

  2. 解决ListView 缓存机制带来的显示不正常问题

    ListView加载数据原理:系统绘制ListView时,首先会用getCount()函数得到要绘制的这个列表的长度,然后开始逐行绘制.然后调用getView()函数,在这个函数里面首先获得一个Vie ...

  3. android 双缓存机制

    废话不多说,直接贴代码! 所谓的双缓存,第一就是缓存在内存里面,第二就是缓存在SD卡里面,当你需要加载数据时,先去内存缓存中查找,如果没有再去SD卡中查找,并且用户可以自选使用哪种缓存! 缓存内存和缓 ...

  4. Android图片加载框架最全解析(三),深入探究Glide的缓存机制

    在本系列的上一篇文章中,我带着大家一起阅读了一遍Glide的源码,初步了解了这个强大的图片加载框架的基本执行流程. 不过,上一篇文章只能说是比较粗略地阅读了Glide整个执行流程方面的源码,搞明白了G ...

  5. Android性能优化之ListView缓存机制

    要想优化ListView首先要了解它的工作原理,列表的显示须要三个元素:ListView.Adapter.显示的数据. 这里的Adapter就是用到了适配器模式,无论传入的是什么View在ListVi ...

  6. Android WebView 缓存机制和模式详解

    当我们加载Html时候,会在我们data/应用package下生成database与cache两个文件夹: 我们请求的Url记录是保存在webviewCache.db里,而url的内容是保存在webv ...

  7. Android笔记(二十五) ListView的缓存机制与BaseAdapter

    之前接触了ListView和Adapter,Adapter将数据源和View连接起来,实际应用中,我们要显示的数据往往有很多,而屏幕只有那么大,系统只能屏幕所能显示的内容,当我们滑动屏幕,会将旧的内容 ...

  8. RecyclerView 源码分析(二) —— 缓存机制

    在前一篇文章 RecyclerView 源码分析(一) -- 绘制流程解析 介绍了 RecyclerView 的绘制流程,RecyclerView 通过将绘制流程从 View 中抽取出来,放到 Lay ...

  9. H5 和移动端 WebView 缓存机制解析与实战

    本文来自于腾讯Bugly公众号(weixinBugly),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/qHm_dJBhVbv0pJs8Crp77w 作者:叶 ...

随机推荐

  1. 找出Active Directory架构操作主机方法!

  2. DUBBO Thread pool is EXHAUSTED!

    一.问题 在测试环境遇到的异常信息,如下: 16-10-17 00:00:00.033 [New I/O server worker #1-6] WARN  com.alibaba.dubbo.com ...

  3. DeDeCMS 每次都被黑出翔了!!DEDECMS漏洞扫描

    在dedecms基础上用插件的形式制作了一分类信息平台.结果问题不断的接踵而至.每次上去扫描一下.各种漏洞.危急代码一堆一堆的.全然被黑出翔了. 之所以这种原因, 1)开源程序的开放性,让全部人都能够 ...

  4. iOS进度指示器——NSProgress

    iOS进度指示器——NSProgress 一.引言 在iOS7之前,系统一直没有提供一个完整的框架来描述任务进度相关的功能.这使得在开发中进行耗时任务进度的监听将什么麻烦,在iOS7之后,系统提供了N ...

  5. isAssignableFrom与instanceof的区别

    1.isAssignableFrom针对的是class对象: 2.instanceof是实例. isAssignableFrom是用来判断一个类Class1和另一个类Class2是否相同或是另一个类的 ...

  6. Android 实现闹钟功能

      原文地址:Android 实现闹钟功能作者:Android_Learners 一.手机闹钟主要用到了AlarmManager类,AlarmManager类提供了访问系统定时服务的途径,开发人员可以 ...

  7. iOS Safari 中点击事件失效的解决办法

    问题描述 当使用委托给一个元素添加click事件时,如果事件是委托到 document 或 body 上,并且委托的元素是默认不可点击的(如 div, span 等),此时 click 事件会失效. ...

  8. 2016年11月2日——jQuery源码学习笔记

    1.jQuery()函数,即$().有四种不同的调用方式. (1)传递CSS选择器(字符串)给$()方法,返回当前文档中匹配该选择器的元素集.可选第二个参数,一个元素或jQuery对象,定义元素查询的 ...

  9. <input value="hidden">的作用

    这样子上个页面的参数可以保存在这个页面,为下个页面获取参数做准备,在这个页面表单提交的时候下个页面可以获取参数

  10. c-八进制 转 十进制

    概述 其实x进制转十进制的算法都差不多,不过如果是针对于字符形式,他们却有点不同.使用指针和数组的形式计算,又不同.这里演示将字符型的数组形式的八进制转成十进制: #include <stdio ...