ListView与GridView优化
前言
ListView是Android中最常用的控件,通过适配器来进行数据适配然后显示出来,而其性能是个很值得研究的话题。本文与你一起探讨Google I/O提供的优化Adapter方案,欢迎大家交流。
声明
欢迎转载,但请保留文章原始出处:)
博客园:http://www.cnblogs.com
农民伯伯: http://over140.cnblogs.com
正文
一、准备
1.1 了解关于Google IO大会关于Adapter的优化,参考以下文章:
Android开发之ListView 适配器(Adapter)优化
Android开发——09Google I/O之让Android UI性能更高效(1)
PDF下载:Google IO.pdf
1.2 准备测试代码:
Activity
private String[] mArrData;
private TextView mTV;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mTV = (TextView) findViewById(R.id.tvShow);
mArrData = new String[1000];
for (int i = 0; i < 1000; i++) {
mArrData[i] = "Google IO Adapter" + i;
}
mAdapter = new TestAdapter(this, mArrData);
((ListView) findViewById(android.R.id.list)).setAdapter(mAdapter);
}
代码说明:模拟一千条数据,TestAdapter继承自BaseAdapter,main.xml见文章末尾下载。
二、测试
测试方法:手动滑动ListView至position至50然后往回滑动,充分利用convertView不等于null的代码段。
2.1 方案一
按照Google I/O介绍的第二种方案,把item子元素分别改为4个和10个,这样效果更佳明显。
2.1.1 测试代码
private long sum = 0L;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//开始计时
long startTime = System.nanoTime();
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text,
null);
}
((ImageView) convertView.findViewById(R.id.icon1)).setImageResource(R.drawable.icon);
((TextView) convertView.findViewById(R.id.text1)).setText(mData[position]);
((ImageView) convertView.findViewById(R.id.icon2)).setImageResource(R.drawable.icon);
((TextView) convertView.findViewById(R.id.text2)).setText(mData[position]);
//停止计时
long endTime = System.nanoTime();
//计算耗时
long val = (endTime - startTime) / 1000L;
Log.e("Test", "Position:" + position + ":" + val);
if (count < 100) {
if (val < 1000L) {
sum += val;
count++;
}
} else
mTV.setText(String.valueOf(sum / 100L));//显示统计结果
return convertView;
}
2.1.2 测试结果(微秒除以1000,见代码)
次数 |
4个子元素 |
10个子元素 |
第一次 |
366 |
723 |
第二次 |
356 |
689 |
第三次 |
371 |
692 |
第四次 |
356 |
696 |
第五次 |
371 |
662 |
按照Google I/O介绍的第三种方案,是把item子元素分别改为4个和10个。
2.2.1 测试代码
private long sum = 0L;
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// 开始计时
long startTime = System.nanoTime();
ViewHolder holder;
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text,
null);
holder = new ViewHolder();
holder.icon1 = (ImageView) convertView.findViewById(R.id.icon1);
holder.text1 = (TextView) convertView.findViewById(R.id.text1);
holder.icon2 = (ImageView) convertView.findViewById(R.id.icon2);
holder.text2 = (TextView) convertView.findViewById(R.id.text2);
convertView.setTag(holder);
}
else{
holder = (ViewHolder)convertView.getTag();
}
holder.icon1.setImageResource(R.drawable.icon);
holder.text1.setText(mData[position]);
holder.icon2 .setImageResource(R.drawable.icon);
holder.text2.setText(mData[position]);
// 停止计时
long endTime = System.nanoTime();
// 计算耗时
long val = (endTime - startTime) / 1000L;
Log.e("Test", "Position:" + position + ":" + val);
if (count < 100) {
if (val < 1000L) {
sum += val;
count++;
}
} else
mTV.setText(String.valueOf(sum / 100L));// 显示统计结果
return convertView;
}
}
static class ViewHolder {
TextView text1;
ImageView icon1;
TextView text2;
ImageView icon2;
}
2.2.2 测试结果(微秒除以1000,见代码)
次数 |
4个子元素 |
10个子元素 |
第一次 |
311 |
417 |
第二次 |
291 |
441 |
第三次 |
302 |
462 |
第四次 |
286 |
444 |
第五次 |
299 |
436 |
此方案为“Henry Hu”提示,API Level 4以上提供,这里顺带测试了一下不使用静态内部类情况下性能。
public View getView(int position, View convertView, ViewGroup parent) {
// 开始计时
long startTime = System.nanoTime();
if (convertView == null) {
convertView = mInflater.inflate(R.layout.list_item_icon_text, null);
convertView.setTag(R.id.icon1, convertView.findViewById(R.id.icon1));
convertView.setTag(R.id.text1, convertView.findViewById(R.id.text1));
convertView.setTag(R.id.icon2, convertView.findViewById(R.id.icon2));
convertView.setTag(R.id.text2, convertView.findViewById(R.id.text2));
}
((ImageView) convertView.getTag(R.id.icon1)).setImageResource(R.drawable.icon);
((ImageView) convertView.getTag(R.id.icon2)).setImageResource(R.drawable.icon);
((TextView) convertView.getTag(R.id.text1)).setText(mData[position]);
((TextView) convertView.getTag(R.id.text2)).setText(mData[position]);
// 停止计时
long endTime = System.nanoTime();
// 计算耗时
long val = (endTime - startTime) / 1000L;
Log.e("Test", "Position:" + position + ":" + val);
if (count < 100) {
if (val < 1000L) {
sum += val;
count++;
}
} else
mTV.setText(String.valueOf(sum / 100L) + ":" + nullcount);// 显示统计结果
return convertView;
}
2.3.2 测试结果(微秒除以1000,见代码)
第一次:450
第二次:467
第三次:472
第四次:451
4.1 首先有一个认识是错误的,我们先来看截图:
可以发现,只有第一屏(可视范围)调用getView所消耗的时间远远多于后面的,通过对
此外了解这个原理了,那么以下代码不运行你可能猜到结果了:
convertView = mInflater.inflate(R.layout.list_item_icon_text, null);
((ImageView) convertView.findViewById(R.id.icon1)).setImageResource(R.drawable.icon);
((TextView) convertView.findViewById(R.id.text1)).setText(mData[position]);
((ImageView) convertView.findViewById(R.id.icon2)).setImageResource(R.drawable.icon);
((TextView) convertView.findViewById(R.id.text2)).setText(mData[position]);
}
else
return convertView;
没错,你会发现滚动时会重复显示第一屏的数据!
子控件里的事件因为是同一个控件,也可以直接放到convertView == null 代码块内部,如果需要交互数据比如position,可以通过tag方式来设置并获取当前数据。
4.2 本文方案一与方案二对比
这里推荐如果只是一般的应用(一般指子控件不多),无需都是用静态内部类来优化,使用第二种方案即可;反之,对性能要求较高时可采用。此外需要提醒的是这里也是用空间换时间的做法,View本身因为setTag而会占用更多的内存,还会增加代码量;而findViewById会临时消耗更多的内存,所以不可盲目使用,依实际情况而定。
4.3 方案三
此方案为“Henry Hu”提示,API Level 4以上支持,原理和方案三一致,减少findViewById次数,但是从测试结果来看效果并不理想,这里不再做进一步的测试。
五、推荐文章
Android,谁动了我的内存(1)
Android 内存泄漏调试
2011-3-30 参见这里(http://www.javaeye.com/topic/971782)的讨论,据此将计划写续篇。
结束
对于Google I/O大会这个优化方案一直抱迟疑态度,此番测试总算是有了更进一步的了解,欢迎大家先测试后交流,看看还有什么办法能够再优化一点。
转载于:https://www.cnblogs.com/lanzhi/p/6469678.html
ListView与GridView优化相关推荐
- 13.ListView和GridView
转载请标明出处: http://blog.csdn.net/yujun411522/article/details/46226001 本文出自:[yujun411522的博客] android组件中 ...
- android通用listview和gridview万能适配器实现的两种方式
Listview和gridview是超级常用组件,于是乎,应该封装一下直接拿来用用而不是每次都写Adapter,这样多么的麻烦是不.虽然国内外大牛都有封装过,但是我总结了两个封装好的Adapter分享 ...
- RecycleView实现ListView和GridView,用menu菜单分别显示
RecycleView实现ListView和GridView的效果显示图: RecycleView的实现步骤: 1.搭建环境:由于RecycleView是在android5.0之后出来的,用来代替li ...
- ListView和GridView的一些杂七八杂的内容
2019独角兽企业重金招聘Python工程师标准>>> 今天加了一天班,算是做编程以来的第一次,也是正式工作以来最心甘情愿的一次,希望能开启勤奋模式,努力学习! 最近公司在做andr ...
- android listView嵌套gridview的使用心得
在开发的过程中可能需要用到listview嵌套gridview的场景,但是在Android中, 不能在一个拥有Scrollbar的组件中嵌入另一个拥有Scrollbar的组件,因为这不科学,会混淆滑动 ...
- Flutter中用ListView嵌套GridView报错异常
Flutter中用ListView嵌套GridView报错异常 参考文章: (1)Flutter中用ListView嵌套GridView报错异常 (2)https://www.cnblogs.com/ ...
- wp8.1 Study7: ListView 和GridView应用
对于列表控件,WP8.1常用的是ListView.GridView.ListBox控件.其中前两个是从第三个继承来的. 1.ListView控件 它是展示垂直列表的,如下图所示.它十分适合展示数据. ...
- Android SimpleAdapter显示ListView、GridView
SimpleAdapter作为一个数据集,主要向ListView.GridView容器填充数据,总结了几种填充方式,原理很简单,直接看代码和效果图 1. ListView单行显示(simple_lis ...
- 如何让listview或者gridview设置到底刷新新数据
昨天简单的看了一下ScrollView的例子,虽然可以实现拉到底触发监听,但是Listview和gridview本身就自带了下拉属性,所以不需要ScrollView来实现. 那么在Listview和g ...
最新文章
- 计算机文档里的东西可以删吗,电脑c盘哪些文件可以删除
- 数据预处理-异常值识别
- ELF文件格式与进程地址空间的联系
- MongoDB负载信息一目了然 阿里云HDM重磅发布MongoDB监控和诊断功
- 如何用VC++新建一个项目
- python连接服务器代码_python服务器端收发请求的实现代码
- 接入腾讯云短信服务(史上最详细+该短信服务如何申请成功+发送短信验证码API讲解+相关错误分析)
- Vivado设置指定源文件进行RTL优化
- mac 如何配置mysql_MAC下安装与配置MySQL
- 学计算机专业能上国家电网吗,高考结束后,选择什么专业能进入国家电网?这些专业考生应该知道...
- [转]awsome-python
- android路上的点点滴滴
- win2003 sp2 设置NLB
- Linux下运行java DES AES加解密
- 笔记本安装linux
- java模拟器下载文件_KEmulator(java模拟器)最新下载
- 江民科技董事长王江民因病在北京逝世 享年59岁
- 大盘点 | 2020年「21篇」医学影像算法最佳综述
- 改注册表让win7/win8中的控制面板项的名字随心所欲
- JavaScript <script>
热门文章
- 0编译器详解_详解Java枚举类型(Enum)中的方法
- python manager详解_python 多进程共享全局变量之Manager()详解
- php收购,php中文网收购全国用户量最大的phpstudy集成开发环境揭秘
- nedc和epa续航里程什么意思_400公里已成续航新起点,纯电动车的实用性到底怎样...
- 陷阱计算机音乐谱大全,陷阱 原版C调-王北车-和弦谱-《弹吧》官网tan8.com-和弦谱大全,学吉他,秀吉他...
- php js 比较,PHP与JS的比较
- java openmp库_OpenMP的环境变量及库函数
- python中dic_python之dic {字典}(重要指数*****)
- linux几秒钟同步一次,Linux时间同步配置方法
- c语言fork()创建线程,操作系统的创建原语是fork()还是creat()?