ListView优化整理
来源:互联网 发布:淘宝网电动三轮车 编辑:程序博客网 时间:2024/06/11 09:18
ListView为什么要使用convertView和ViewHolder
原因就是:
1. 使用convertView可以避免重复地调用inflate
2. 使用ViewHolder可以避免重复地调用findViewById
首先讲下ListView的原理:ListView中的每一个Item显示都需要Adapter调用一次getView的方法,这个方法会传入一个convertView的参数,返回的View就是这个Item显示的View。如果当Item的数量足够大,再为每一个Item都创建一个View对象,必将占用很多内存,创建View对象(mInflater.inflate(R.layout.lv_item, null);从xml中生成View,这是属于IO操作)也是耗时操作,所以必将影响性能。Android提供了一个叫做Recycler(反复循环器)的构件,就是当ListView的Item从上方滚出屏幕视角之外,对应Item的View会被缓存到Recycler中,相应的会从下方生成一个Item,而此时调用的getView中的convertView参数就是滚出屏幕的Item的View,所以说如果能重用这个convertView,就会大大改善性能。
以下是最简单的使用viewHolder和convertView的代码
- /**
- * Make a view to hold each row.
- *
- * @see android.widget.ListAdapter#getView(int, android.view.View,
- * android.view.ViewGroup)
- */
- public View getView(int position, View convertView, ViewGroup parent) {
- // A ViewHolder keeps references to children views to<span style="color:#ff0000;"> avoid unneccessary calls
- // to findViewById()</span> on each row.
- ViewHolder holder;
- // When convertView is not null, we can reuse it directly, <span style="color:#ff0000;">there is no need
- // to reinflate it.</span> We only inflate a new View when the convertView supplied
- // by ListView is null.
- if (convertView == null) {
- convertView = mInflater.inflate(R.layout.list_item_icon_text, null);
- // Creates a ViewHolder and store references to the two children views
- // we want to bind data to.
- holder = new ViewHolder();
- holder.text = (TextView) convertView.findViewById(R.id.text);
- holder.icon = (ImageView) convertView.findViewById(R.id.icon);
- convertView.setTag(holder);
- } else {
- // Get the ViewHolder back to get fast access to the TextView
- // and the ImageView.
- holder = (ViewHolder) convertView.getTag();
- }
- // Bind the data efficiently with the holder.
- holder.text.setText(DATA[position]);
- holder.icon.setImageBitmap((position & 1) == 1 ? mIcon1 : mIcon2);
- return convertView;
- }
1、原因分析
ListView item缓存机制:为了使得性能更优,ListView会缓存行item(某行对应的View)。ListView通过adapter的getView函数获得每行的item。滑动过程中,a. 如果某行item已经滑出屏幕,若该item不在缓存内,则put进缓存,否则更新缓存;
b. 获取滑入屏幕的行item之前会先判断缓存中是否有可用的item,如果有,做为convertView参数传递给adapter的getView。
更具体可见源代码ListView.obtainView。这样,如下的getView写法就可以充分利用缓存大大提升ListView的性能。即便上万个行item,最多inflate的次数为n,n为一屏最多显示ListView 行item的个数。
ListView Adapter getView写法123456789101112@Overridepublic View getView ( int position , View convertView , ViewGroup parent ) {ViewHolder holder ;if ( convertView == null ) {convertView = inflater . inflate ( R . layout . list_item , null ) ;holder = new ViewHolder ( ) ;……convertView . setTag ( holder ) ;} else {holder = ( ViewHolder ) convertView . getTag ( ) ;}}这样提升了性能,但同时也会造成另外一些问题:
a. 行item图片显示重复
这个显示重复是指当前行item显示了之前某行item的图片。
比如ListView滑动到第2行会异步加载某个图片,但是加载很慢,加载过程中listView已经滑动到了第14行,且滑动过程中该图片加载结束,
第2行已不在屏幕内,根据上面介绍的缓存原理,第2行的view可能被第14行复用,这样我们看到的就是第14行显示了本该属于第2行的图片,
造成显示重复。
b. 行item图片显示错乱
这个显示错乱是指某行item显示了不属于该行item的图片。
比如ListView滑动到第2行会异步加载某个图片,但是加载很慢,加载过程中listView已经滑动到了第14行,第2行已不在屏幕内,根据上面介绍的缓存原理,第2行的view可能被第14行复用,第14行显示了第2行的View,这时之前的图片加载结束,就会显示在第14行,造成错乱。
c. 行item图片显示闪烁
上面b的情况,第14行图片又很快加载结束,所以我们看到第14行先显示了第2行的图片,立马又显示了自己的图片进行覆盖造成闪烁错乱。
/**
* 显示这个图片,解决了列表问题.
* 列表问题:滑动过程中,getView的imageView会重复利用,导致图片会串位
* @param imageView 显得的View
* @param url the url
* @return
*/
public
void
display(
final
ImageView imageView,String url) {
if
(AbStrUtil.isEmpty(url)){
if
(noImage !=
null
){
if
(loadingView !=
null
){
loadingView.setVisibility(View.INVISIBLE);
imageView.setVisibility(View.VISIBLE);
}
imageView.setImageDrawable(noImage);
}
return
;
}
//设置下载项
final
AbImageDownloadItem item =
new
AbImageDownloadItem();
//设置显示的大小
item.width = width;
item.height = height;
//设置为缩放
item.type = type;
item.imageUrl = url;
final
String cacheKey = AbImageCache
.getCacheKey(item.imageUrl, item.width, item.height, item.type);
item.bitmap = AbImageCache.getBitmapFromCache(cacheKey);
//if(D) Log.d(TAG, "缓存中获取的"+cacheKey+":"+item.bitmap);
//设置标记
imageView.setTag(url);
if
(item.bitmap ==
null
){
//先显示加载中
if
(loadingView!=
null
){
loadingView.setVisibility(View.VISIBLE);
imageView.setVisibility(View.INVISIBLE);
}
else
if
(loadingImage !=
null
){
imageView.setImageDrawable(loadingImage);
}
//下载完成后更新界面
item.setListener(
new
AbImageDownloadListener() {
@Override
public
void
update(Bitmap bitmap, String imageUrl) {
//未设置加载中的图片,并且设置了隐藏的View
if
(loadingView !=
null
&& imageUrl.equals(imageView.getTag())){
loadingView.setVisibility(View.INVISIBLE);
imageView.setVisibility(View.VISIBLE);
}
//要判断这个imageView的url有变化,如果没有变化才set,
//有变化就取消,解决列表的重复利用View的问题
if
(bitmap!=
null
&& imageUrl.equals(imageView.getTag())){
if
(D) Log.d(TAG,
"图片下载,设置:"
+imageUrl);
imageView.setImageBitmap(bitmap);
}
else
{
if
(errorImage !=
null
&& imageUrl.equals(imageView.getTag())){
imageView.setImageDrawable(errorImage);
}
}
}
});
if
(D) Log.d(TAG,
"图片下载,执行:"
+url);
mAbImageDownloadPool.execute(item);
}
else
{
if
(loadingView !=
null
){
loadingView.setVisibility(View.INVISIBLE);
imageView.setVisibility(View.VISIBLE);
}
imageView.setImageBitmap(item.bitmap);
}
}
但是 在图片加载慢时,会出现listView显示空白现象,那就需要美工将公司logo设计成一个展示的item,默认展示公司logo,加载出图片就正常显示。
- ListView优化整理
- ListView的优化整理
- ListView优化整理
- ListView优化
- listView优化
- ListView优化
- ListView优化
- ListView优化
- ListView优化
- listView优化
- listview 优化
- ListView优化
- listView优化
- ListView 优化
- ListVIew优化
- ListView优化
- ListView优化
- listview优化
- Dubbo源码学习之知识点分析(续)
- C语言学习篇-1Hello, World!(编写、编译、链接、运行)
- android httpclient 设置超时
- 算法菜鸟Leetcode之旅-1
- hive的学习笔记2-hive源码的编译
- ListView优化整理
- Scala隐式转换之隐式参数(1)
- 开始写blog了
- html5--canvas学习
- 关于PDB与DLL
- 安装tushare库
- 第一篇博文
- gbk编码表
- Leetcode 172. Factorial Trailing Zeroes