ListView——缓存与优化剖析总结

嵌入式GUI开发:emWin LISTVIEW控件从入门到精通 在嵌入式系统开发中,GUI(图形用户界面)是连接用户与设备的关键桥梁,其核心在于高效管理界面元素与用户交互。表格数据展示作为高频需求,其实现原理涉及数据模型、视图渲染与消息循环的协同。通过控件技术,开发者能够构建灵活、响应迅速的人机交互界面,这在工业HMI、消费电子和医疗设备等场景中尤为重要。emWin作为嵌入式领域广泛应用的图形库,其LISTVIEW控件正是为此类需求设计的强大工具,它通过分离数据、视图与交互逻辑,并支持Owner-Draw自绘机制,允许深度定制单元格渲染,从而满足斑马纹、图标集成和条件格 阅读详情

ListView 缓存机制

单类型Item

在这里插入图片描述
上图B代表View的类型,1/2/3代表在ListView中第几个位置。

ListView的缓存池是ListView的父类AbsListView的内部类RecycleBin里面的一个ArrayList的数组。

ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];

看上图的List列表,当状态1变为状态2时,1B滑出6B滑入,此时scrapViews[0]中还没有缓存的View,所以6B创建,1B进入缓存。

状态2变为状态3时。缓存中存在B类型的元素,所以直接拿出来复用。

在这里插入图片描述

多类型Item

多类型机制和单类型区别不大,如下图示。

在这里插入图片描述
状态1到状态2,1A进入scrapViews[0]的缓存。

状态2到状态3,1A复用,2B进入scrapViews[1]缓存。

缓存剖析

 	/**
     * 根据数据列表的position返回需要展示的layout的对应的type
     * type的值必须从0开始 
     */
    @Override
    public int getItemViewType(int position) { 
    	return 0;
    }

    /**
     * 该方法返回多少个不同的布局
     */
    @Override
    public int getViewTypeCount() {
        return 1;
    }
 

这两个方法是BaseAdapter里面的,用于设置多Item的。

getItemViewType() 根据列表的position加载指定的Item。

getViewTypeCount() 返回Item的个数。这决定了scrapViews 数组的长度。

ListView缓存原理由它的父类AbsListView的内部类RecycleBin负责。

下面源码是对缓冲池的初始化。

        public void setViewTypeCount(int viewTypeCount) {
            if (viewTypeCount < 1) {
                throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
            }
            //noinspection unchecked
            ArrayList<View>[] scrapViews = new ArrayList[viewTypeCount];
            for (int i = 0; i < viewTypeCount; i++) {
                scrapViews[i] = new ArrayList<View>();
            }
            mViewTypeCount = viewTypeCount;
            mCurrentScrap = scrapViews[0];
            mScrapViews = scrapViews;
        }

可以看出,缓存大小取决于BaseAdapter getViewTypeCount()的返回值。

下面这个方法是每次初始化都会调用的。

    private void setItemViewLayoutParams(View child, int position) {
        final ViewGroup.LayoutParams vlp = child.getLayoutParams();
        LayoutParams lp;
        if (vlp == null) {
            lp = (LayoutParams) generateDefaultLayoutParams();
        } else if (!checkLayoutParams(vlp)) {
            lp = (LayoutParams) generateLayoutParams(vlp);
        } else {
            lp = (LayoutParams) vlp;
        }

        if (mAdapterHasStableIds) {
            lp.itemId = mAdapter.getItemId(position);
        }
        lp.viewType = mAdapter.getItemViewType(position);
        lp.isEnabled = mAdapter.isEnabled(position);
        if (lp != vlp) {
          child.setLayoutParams(lp);
        }
    }

注意到

lp.viewType = mAdapter.getItemViewType(position);

这句的意思是给view的参数设置上它的类型,但是这个类型是调用getItemViewType()得到的,所以我们需要重写getItemViewType()方法,让相同类型的View返回同一个值。

下面是AbsListView.obtainView()函数,该函数的作用是绘制每一行的View

View obtainView(int position, boolean[] isScrap) {  
    isScrap[0] = false;  
    View scrapView; 
    scrapView = mRecycler.getScrapView(position);  
    // 根据position获取缓存的View
    View child;  
    if (scrapView != null) {  
    	// 如果不为null便可复用convertView
        child = mAdapter.getView(position, scrapView, this);  
        if (child != scrapView) {
        	// 和缓存中的不同的话,就重新存进去。
            mRecycler.addScrapView(scrapView);  
            if (mCacheColorHint != 0) {  
                child.setDrawingCacheBackgroundColor(mCacheColorHint);  
            }  
        } else {  
            isScrap[0] = true;  
            dispatchFinishTemporaryDetach(child);  
        }  
    } else {  
    	// 缓存为null的话,传递convertView为null
        child = mAdapter.getView(position, null, this);  
        if (mCacheColorHint != 0) {  
            child.setDrawingCacheBackgroundColor(mCacheColorHint);  
        }  
    }  
    return child;  
}  

关于如何获得缓存的View,代码里面的注释已经写的很清楚了。

参考
https://blog.youkuaiyun.com/geekerhw/article/details/52176914
https://hit-alibaba.github.io/interview/Android/basic/ListView-Optimize.html
https://www.jianshu.com/p/2791bc155b65

ListView优化

缓存优化

使用ListView自带的缓存优化。
上面也分析了,BaseAdapter自身的缓存原理。
ListView的Adapter的作用如下所示。
在这里插入图片描述

1. 复用convertView

一情况下getView()是是这样写的

   @Override
   public View getView(int position, View convertView, ViewGroup parent) { 
       View view = View.inflate(MainActivity.this, R.layout.listview_item, null); 
       TextView tv_item = (TextView) view.findViewById(R.id.tv_item);
       tv_item.setText(list.get(position));
       return view;
   } 

在上面你的缓存原理可以知道,在得到Item时会首先在缓存中找。

   child = mAdapter.getView(position, scrapView, this);  

当找到后会调用getView()并传入找到的缓存scrapView,此时我们应该在getView中对convertView进行复用。所以如果每次都进行View.inflate(MainActivity.this, R.layout.listview_item, null);缓存就失去了意义。

所以在getView中如果convertView不为null就要对其复用。更改为如下代码。

  public View getView(int position, View convertView, ViewGroup parent) {
      View view;
      // 判断convertView的状态,来达到复用效果
      if(null == convertView){
          //如果convertView为空,则表示第一次显示该条目,需要创建一个view
          view = View.inflate(Main1Activity.this,R.layout.listview_item,null);
      }else{
          //否则表示可以复用convertView
          view = convertView;
      }
      TextView textView =(TextView) view.findViewById(R.id.tv_item);
      textView.setText(list.get(position));
      return view;
  } 

2. 缓存Item条目

findViewById()这个方法是比较耗性能的操作,因为这个方法要找到指定的布局文件,进行不断地解析每个节点:从最顶端的节点进行一层一层的解析查询,找到后在一层一层的返回,如果在左边没找到,就会接着解析右边,并进行相应的查询,直到找到位置。因此可以对findViewById进行优化处理。

解决:定义控件引用的类ViewHolder

优化后的代码:

   public class MyAdapter extends BaseAdapter{ 
	······		
       @Override
       public View getView(int position, View convertView, ViewGroup parent) {
           ViewHolder  viewHolder;
           if(null == convertView){
               convertView = View.inflate(MainActivity.this,R.layout.listview_item,null);
               viewHolder = new ViewHolder();
               viewHolder.textView = (TextView) convertView.findViewById(R.id.tv_item);
               convertView.setTag(viewHolder);
           }else{
               viewHolder = (ViewHolder) convertView.getTag();
           }

           viewHolder.textView.setText(list.get(position));
           return convertView;
       }
   }
   static class ViewHolder{
       TextView textView;
   }

参考
https://blog.youkuaiyun.com/u013278940/article/details/52923807

其他优化

······

Flutter高手进阶:PageView的cacheExtent原理与自定义预加载控件开发 本文深入解析Flutter中PageView的缓存机制,揭示其性能瓶颈,并提供自定义预加载控件开发方案。通过重写viewportBuilder和动态计算cacheExtent,实现高效页面预加载,显著提升滑动流畅度。文章包含完整实现代码、性能优化技巧及复杂场景应用指南,帮助开发者解决PageView卡顿问题。 阅读详情

相关推荐

Android高效图片异步加载实战:ListView、GridView与ViewPager集成

UIL的强大之处在于高度可定制。你可以根据业务需求精细调优每一个环节。你可能会问:UIL现在都不维护了,为什么还要花时间学它?答案很简单:思想永不过时。尽管Glide、Picasso等新框架在API易用性和功能丰富度上更胜一筹,但它们的核心理念——异步加载、三级缓存、内存控制、请求调度——全都源自UIL这类早期探索者。理解UIL,就像是学习计算机组成原理。你知道现在的CPU有多复杂,但只有搞懂了冯·诺依曼架构,才能真正明白计算机是怎么工作的。所以,下次当你轻松写下。

weixin_42593130的博客 1099

Android学习之ListView缓存机制分析

一、ListView的继承结构 ListView是直接继承自的AbsListView,而AbsListView有两个子实现类,一个是ListView,另一个就是GridView,因此ListView和GridView在工作原理和实现上都是有很多共同点的。 AbsListView又继承自AdapterView,AdapterView继承自ViewGroup 二、Adapter的作用 适配器 List...

u013087553的博客 454

ListView缓存机制

ListView缓存机制ListView缓存机制ListView缓存机制ListView缓存机制

ListView和GridView的缓存机制及measure过程

Android进阶之路系列:http://blog.youkuaiyun.com/column/details/16488.html在Android开发中我们经常使用ListView和GridView,它们都有一套缓存机制,通过复用防止view的不停创建。ListView和GridView都是AbsListView的子类,使用其内部类RecycleBin来进行view的缓存。1、View的Transient状......

公众号:BennuCTech 862

Python爬虫实战:西瓜视频m3u8解析与FFmpeg下载合并

网络爬虫与流媒体解析是Python工程实践中的常见需求,其核心在于通过HTTP请求获取数据并解析特定格式。m3u8作为HLS协议索引文件,将视频切分为ts分片,便于流式传输。结合FFmpeg的多线程处理能力,可高效完成分片下载与合并,技术价值在于提升视频处理效率。典型应用场景包括视频下载、离线缓存等。本文以西瓜视频为例,详细讲解如何使用requests库提取m3u8地址,并调用FFmpeg批量下载ts分片合并为mp4,涵盖请求伪装、索引解析及常见问题排查。

weixin_31856057的博客 15万+

(秋招)vins中的光流法

那么下一层基于这个初值也会得到一个解,就这样进行迭代,直到达到金字塔的最底层,也即第0层,就是原始分辨率的那张图片,此时光流法就会给出一个速度值,这个值是比较可靠的(相比对原始图片直接使用光流法来说)。2.小运动,这个也必须满足,就是时间的变化不会引起位置的剧烈变化,这样灰度才能对位置求偏导(换句话说,小运动情况下我们才能用前后帧之间单位位置变化引起的灰度变化去近似灰度对位置的偏导数),这也是光流法不可或缺的假定。可以看到光流法是来估计物体运动的(估计的是物体运动的速度,根据速度再计算相对应的特征点)。

努力coding 651

移动APP测试-ListView优化之内存缓存

内存缓存:内 存优化是将获取到的数据存入到Map集合中,如果再次引用此数据,就直接从Map集合中获取,这样会导致一个问题,如果Map集合中的数据特别多,比如存 取了100万条数据,这样有可能就会导致内存溢出。这是因为Map集合是强引用的集合,如何不把Map集合置为空的话,这个集合Java虚拟机就不会把它 回收掉,当Map中的数据大小超过了内存大小就会导致内存溢出。

软件测试技术交流分享 172

UWB学习——day4

总的来说,BPM-BPSK调制方案是一种利用脉冲位置和相位来编码信息的高效数字调制技术,特别适用于UWB通信系统,以实现高速数据传输和频谱效率。这种方式将时间和相位综合使用,从而提高了数据传输的容量。总之,超外差结构是一种接收器设计,通过将不同频率的信号转换到一个共同的中间频率来提高信号选择性和抗干扰性。超外差结构是一种用于接收器的电子电路设计,它的目标是从无线信号中提取有用的信息,比如音频、数据或图像。该芯片的接收机是超外差结构,所谓超外差结构一种基于频率转换的接收器架构,旨在提高信号选择性和抗干扰性。

许帅的博客 2556

ListView缓存机制讲解

Glide+ListView详解 AndroidStudio配置 implementation 'com.github.bumptech.glide:glide:4.7.1' implementation 'com.android.support:support-v4:27.1.1' Activity 代码 public class GlideListViewA...

听海的博客 1498

PCB设计必看:铜皮厚度与载流能力对照表(附Excel计算工具)

本文深入解析了PCB设计中铜皮厚度与载流能力的核心关系,提供了基于IPC-2152标准的动态计算逻辑与实用Excel工具。文章不仅分享了载流对照表,更重点剖析了影响载流能力的关键因素(如铜厚、线宽、温升、布线层),并给出了高电流设计的实战技巧与测试验证方法,帮助工程师规避常见陷阱,实现从理论到实践的闭环设计。

weixin_29228781的博客 721

TCGA之GDC-client工具下载安装与使用

文章主要是对GDC-client工具下载TCGA数据库数据整个过程的一个记录 1.下载GDC-client工具 GDC-client工具网址:GDC Data Transfer Tool | NCI Genomic Data Commons (cancer.gov) 我这里下的是上图中红圈中的版本, 2.解压安装 从网上了解的是不能解压到带中文的路径里,解压后是一个.exe文件,为了能直接在cmd命令行下使用,将其加入系统环境: 点击新建之后,输入将文件解压到的路径,然后...

better_strong的博客 1万+

ListView缓存机制小结

文章目录ListView缓存机制小结前言概述layout过程第一次Layout第二次Layout滑动事件参考资料 ListView缓存机制小结 前言 由于本人水平有限,如果文章中出现一些谬误,还请各位大佬指正。 概述 ListView的缓存通过父类AbsListView中的内部类RecycleBin实现,这个类中有两级缓存:ActiveViews 和ScrapViews ActiveViews用来缓存滑动后还留在屏幕内的itemview,供layout过程使用 ScrapViews用来缓存滑出ListVi

qq_43935080的博客 649

【SystemVerilog笔记(一)】数据类型

(一)内建数据类型 1.按照四值逻辑和二值逻辑分类 四值逻辑类型:integer、logic、reg、wire等线网类型 二值逻辑类型:byte、shortint、int、longint、bit 2.按照有符号和无符号分类 有符号类型:byte、shortint、int、longint、integer 无符号类型:bit、logic、reg、wire等线网类型 ※记忆:按位定义的变量是无符号的。 (二)软件常用类型 1.定宽数组 在这里插入代码片 ...

cc__cc__的博客 1万+

ListView复用和优化详解

前言 我们每一个Android开发人员对ListView的使用肯定是很熟悉的,然而多少人能真正的懂ListView的缓存机制呢,说白了就是ListView为了提高效率而内部实现的一种优化,而这种优化就需要复用ItemView(也就是item对应的View).那么下面楼主来对ListView和RecyclerView的item复用问题做一个深入的讲解

小金子的专栏 1万+

大数据架构中的数据治理:元数据管理与数据血缘追踪实践

本文将聚焦大数据架构中数据治理的两大核心支柱——元数据管理与数据血缘追踪元数据管理的目标、类型与实施步骤(从需求分析到工具落地);数据血缘追踪的技术实现(静态解析、动态捕获、混合方案)与应用场景;如何将两者结合,构建完整的数据治理体系,并通过真实案例展示落地效果。元数据管理:定义了业务/技术/操作元数据,讲解了工具选型(如Apache Atlas)、采集(Hook/API)、存储(关系库+图数据库)、应用(数据发现、质量监控);数据血缘追踪。

欢迎来到我的优快云空间!这里聚焦AI大模型应用实战,分享前沿技术、实战案例与开发经验。 867

linux内核学习(八)---摄像头框架移植(上)

本章来开始进行摄像头的移植,同时回顾一下V4L2的整个框架

文艺小少年的博客 113

Android ListView滑动过程中图片显示重复错位闪烁问题解决

之前对ListView理解有误,参考资料:ListView适配器及缓存机制http://www.apkbus.com/android-48459-1-1.html,

LGL的专栏 1008

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Android面试必备:RecyclerView与ListView深度对比与实战解析

本文深度解析了Android开发中RecyclerView与ListView的核心差异,涵盖设计哲学、缓存机制、布局灵活性及数据更新策略。重点剖析了RecyclerView的四级缓存体系、模块化设计带来的优势,并提供了性能优化实战技巧与面试回答策略,是Android开发者应对相关面试题的必备指南。

weixin_29246195的博客 350

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

android listview 异步加载图片并防止错位

网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertView 但没有异步操作也不会有问题。 我简单分析一下: 当重用 convertView 时,最初一屏显示 7 条记录, getView 被调用 7 次,创建了 7 个 convertVi

Fenice 1731

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

ListView工作原理、卡顿及OOM--android

ListView卡顿或UI卡顿:   1..Adapter的getView方法里面convertView没有使用setTag和getTag方式;   2.在getView方法里面ViewHolder初始化后的赋值或者是多个控件的显示状态和背景的显示没有优化好,抑或是里面含有复杂的计算和耗时操作;   3.在getView方法里面 inflate的row 嵌套太深(布局过于复杂)或者是布局

ShareUs的专栏 746

虚幻引擎UMG 5.8 性能优化3要点:避免绑定/Tick,善用缓存与事件

本文深入探讨了虚幻引擎UMG 5.8性能优化的三大核心策略:避免属性绑定与Tick事件、善用控件缓存与复用机制、采用事件驱动架构。通过实测数据对比和代码示例,展示了如何从卡顿UI实现丝滑体验,特别适合开发大型项目的虚幻引擎开发者参考。

cuizhu0832的博客 414

深入解析QML ListView:模型、代理与性能优化实战指南

在UI开发中,列表视图是展示线性数据集合的基础组件,其核心基于模型-视图-代理(MVA)架构。该架构通过数据模型(Model)管理原始数据,视图组件(View)负责布局与滚动,而代理(Delegate)则定义每个数据项的视觉呈现与交互逻辑。这种分离设计提升了代码的可维护性和复用性,尤其在处理动态数据更新时,能实现高效的增量渲染而非整体刷新,对于构建流畅的长列表界面至关重要。在实际工程中,开发者常面临数据绑定、滚动性能、内存管理等挑战。本文聚焦于QML中的ListView组件,针对其模型更新策略、代理项优化、

weixin_32612263的博客 318

【Flutter for OpenHarmony 第三方库】 Flutter for OpenHarmony 底部导航栏实战:踩坑指南与性能优化

说实话,当你第一次尝试在 Flutter for OpenHarmony 上实现底部导航栏时,你会发现自己掉进了一个巨大的坑里。官方文档写得云淡风轻,仿佛一切都是那么简单自然。但现实是残酷的——你会在各种奇怪的问题上浪费大量时间,从页面切换卡顿到状态管理混乱,再到内存泄漏问题层出不穷。今天,我就要把这些血泪史毫无保留地分享出来,让你少走弯路。本文将基于一个真实的待办清单应用(已成功运行在 OpenHarmony 设备上),深度剖析底部导航栏的实现细节和那些让人抓狂的踩坑点。问题解决方案优先级。

junhong_junhong的博客 406

android中级开发师必备_2019初中级Android开发社招面试解答之性能优化

注:因为实际开发与参考答案会有所不同,再者怕误导大家,所以这些面试题答案还是自己去理解!面试官会针对简历中提到的知识点由浅入深提问,所以不要背答案,多理解。1.图片的三级缓存中,图片加载到内存中,如果内存快爆了,会发生什么?怎么处理?参考回答:首先我们要清楚图片的三级缓存是如何的如果内存足够时不回收。内存不够时就回收软引用对象2.内存中如果加载一张500X500的png高清图片.应该是占用多少的内...

weixin_42499882的博客 177

【MAUI布局控件终极优化】:3步解决界面卡顿,响应速度提升10倍

3步优化MAUI的控件布局,彻底解决界面卡顿问题。适用于复杂页面与高频交互场景,通过延迟加载、控件复用和布局简化显著提升响应速度,实测性能提升10倍。值得收藏

IterStream的博客 668
上一篇: Android——消息机制
下一篇: RecyclerView——缓存回收机制剖析总结
PdKingLiu
博客等级 码龄9年 89粉丝 92原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值