ListView与GridView优化
前言
ListView是Android中最常用的控件,通过适配器来进行数据适配然后显示出来,而其性能是个很值得研究的话题。本文与你一起探讨Google I/O提供的优化Adapter方案,欢迎大家交流。
正文
一、准备
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次数,但是从测试结果来看效果并不理想,这里不再做进一步的测试。
五、推荐文章
2011-3-30 参见这里(http://www.javaeye.com/topic/971782)的讨论,据此将计划写续篇。
结束
对于Google I/O大会这个优化方案一直抱迟疑态度,此番测试总算是有了更进一步的了解,欢迎大家先测试后交流,看看还有什么办法能够再优化一点。
ListView与GridView优化的更多相关文章
- Android之ListView/GridView 优化
一.效率最低的getView实现 我们知道,ListView和GridView的显示都是通过Adapter的getView实现的. ListView/GridView数据量较小时,我们的处理方式一般是 ...
- [Android Pro] listView和GridView的item设置的高度和宽度不起作用
referece to : http://blog.csdn.net/beibeixiao/article/details/9032569 1. 在Android开发中会发现,有时listVi ...
- android 有弹性的ScrollView 简单实现,与处理ScrollView和ListView,GridView之间的冲突
处理ScrollView和ListView,GridView之间的冲突, 最好的办法就是继承这两个类,重写他们的onMeasure方法即可: ListView: import android.widg ...
- Android之ScrollView嵌套ListView和GridView冲突
由于ListView,GridView本身都继承于ScrollView,一旦在ScrollView中嵌套ScrollView, 在ScrollView中嵌套使用ListView或者GridView,L ...
- [安卓] 16、ListView和GridView结合显示单元实现自定义列表显示效果
List在各种手机应用中都有体现,是安卓UI设计的必修课. 本文将介绍在开发中如何利用ListView和GridView设计自定义列表. 下面分别是用ListView和GridView做的效果: 上面 ...
- android listView嵌套gridview的使用心得
在开发的过程中可能需要用到listview嵌套gridview的场景,但是在Android中, 不能在一个拥有Scrollbar的组件中嵌入另一个拥有Scrollbar的组件,因为这不科学,会混淆滑动 ...
- (转)解决ScrollView嵌套ListView或者GridView导致只显示一行的方法
即动态获取ListView和GridView的高度 一.对于ListView ListView listview= new ListView(this); setListViewHeightBased ...
- Listview和Gridview自定义分割线
1,ListView和GridView中的每一个条目都有分割线,属性android:footerDividersEnabled表示是否显示分割线,默认是为true,即可见.可以自定义的设置分割线的颜色 ...
- android 项目学习随笔十七(ListView、GridView显示组图)
ListView.GridView显示组图,处理机制相同 <?xml version="1.0" encoding="utf-8"?> <Li ...
随机推荐
- bootstrap 时间控件带(时分秒)选择器(需要修改才能显示,请按照参数说明后面的步骤进行修改)
1.控件下载地址:http://www.bootcss.com/p/bootstrap-datetimepicker/index.htm,参数设置说明也在这个链接下面: 2.具体参数说明(复制原链接) ...
- Maven报错Missing artifact jdk.tools:jdk.tools:jar:1.7--转
原文地址:http://blog.csdn.net/u013281331/article/details/40824707 在Eclipse中检出Maven工程,一直报这个错:“Missing art ...
- 8.2 Android灯光系统_led_class驱动
android-5.0.2\hardware\libhardware\include\hardware\lights.h //系统一些宏定义 android源码只带的灯光驱动在linux内核的dri ...
- [Angular] HostListener Method Arguments - Blocking Default Keyboard Behavior
We are going to see how to using method arguments for @HostListener. First, we can use HostListener ...
- C#实现人脸识别
C#实现基于ffmpeg加虹软的人脸识别 关于人脸识别 目前的人脸识别已经相对成熟,有各种收费免费的商业方案和开源方案,其中OpenCV很早就支持了人脸识别,在我选择人脸识别开发库时,也横向对比了三种 ...
- GDB如何调试没有符号表(未加-g选项的编译)的程序
/********************************************************************* * Author : Samson * Date ...
- VS2012调试C++工程DLL
1.C++工程属性对话框 2.配置属性: (1)常规:输出目录:..\Bin\WFCrawler(调用DLL的工程) 中间目录:..\Bin\WFCrawler(调用DLL的工程 ...
- 格式化上下文formatting contexts
原文 简书原文:https://www.jianshu.com/p/20c32c367b63 什么是格式化上下文(formatting contexts) Formatting context是W3C ...
- 【note】缩写词
CoE CANopen EtherCAT应用程序概要文件CANopen™是一个注冊商标的能够自己主动化汽车集团..纽伦堡.德国CiA402CANopen™驱动器配置文件里指定的IEC 61800-7- ...
- hadoop调优之一:概述 分类: A1_HADOOP B3_LINUX 2015-03-13 20:51 395人阅读 评论(0) 收藏
hadoop集群性能低下的常见原因 (一)硬件环境 1.CPU/内存不足,或未充分利用 2.网络原因 3.磁盘原因 (二)map任务原因 1.输入文件中小文件过多,导致多次启动和停止JVM进程.可以设 ...