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

转自:http://www.oschina.net/question/221817_121051

主要分析Android ListView滚动过程中图片显示重复、错乱、闪烁的原因及解决方法,顺带提及ListView的缓存机制。
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写法

Java

1

2

3

4

5

6

7

8

9

10

11

12

@Override

public 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行的图片,立马又显示了自己的图片进行覆盖造成闪烁错乱。

2、解决方法
通过上面的分析我们知道了出现错乱的原因是异步加载及对象被复用造成的,如果每次getView能给对象一个标识,在异步加载完成时比较标识与当前行item的标识是否一致,一致则显示,否则不做处理即可。
下面以使用ImageCache为ListView提供图片获取缓存为例,ListView中强烈推荐使用ImageCache
首先在listview adapter的getView中添加

Java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

@Override

public 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 ( ) ;

}

……

// add tag for image, to compare it when image loaded finish

imageView . setTag ( imageUrl ) ;

// if not in cache, restore default

if ( ! Cache . ICON_CACHE . get ( imageUrl , imageView ) ) {

imageView . setImageDrawable ( null ) ;

}

}

其中setTag表示设置标识,方便下面进行标志比对

1

if ( ! Cache . ICON_CACHE . get ( imageUrl , imageView ) )

Cache.ICON_CACHE为ImageCache的实例,表示如果不在缓存内则设置drawable为null(当然你可以可以设置为你自己的默认资源),防止显示了之前某个行item的图片,解决了a. 行item图片显示重复问题。

在ImageCache的OnImageCallbackListener的onImageLoaded函数中添加

Java

1

2

3

4

5

6

7

8

9

10

11

public void onImageLoaded ( String imageUrl , Drawable imageDrawable , View view , booleanisInCache ) {

// can be another view child, like textView and so on

if ( view != null && imageDrawable != null ) {

ImageView imageView = ( ImageView ) view ;

// add tag judge, avoid listView cache and so on

String imageUrlTag = ( String ) imageView . getTag ( ) ;

if ( ObjectUtils . isEquals ( imageUrlTag , imageUrl ) ) {

imageView . setImageDrawable ( imageDrawable ) ;

}

}

} ;

时间: 2024-08-06 20:05:24

Android ListView滑动过程中图片显示重复错乱闪烁问题解决的相关文章

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

转自:here 主要分析Android ListView滚动过程中图片显示重复.错乱.闪烁的原因及解决方法,顺带提及ListView的缓存机制.1.原因分析ListView item缓存机制:为了使得性能更优,ListView会缓存行item(某行对应的View).ListView通过adapter的getView函数获得每行的item.滑动过程中, a. 如果某行item已经滑出屏幕,若该item不在缓存内,则put进缓存,否则更新缓存:b. 获取滑入屏幕的行item之前会先判断缓存中是否有可

Android ListView滑动过程中控件显示重复/错误问题之原理分析及解决方案

前言: 为了使ListView性能更优,最普遍的方法就是添加一个ViewHolder静态类. 虽然性能有很大的提高,但是同样也伴随着Item控件内容显示重复或错乱的情况. 分析并解决如下两个问题 一.控件数据未初始化而导致的显示错误. 二.网络异步加载导致出现显示错误.重复. 如下我们来简单分析一下ListView的缓存机制.我们整篇文章均以下图的模型来举例说明. (图片转至http://www.cnblogs.com/xiaowenji/archive/2010/12/08/1900579.h

android listview 滑动过程中不加载图片,停止时加载图片

今天闲来无事, 就测试了一下listview加载图片优化的功能, 在我们使用新浪微博的时候,细心的同学一定发现了,在滑动的过程中,图片是没有被加载的, 而是在滑动停止时,才加载图片了. 我们今天就做一个这样的效果吧. 我们先考虑两个问题: 1.在滑动停止的时候,如何获得需要加载的图片控件? 2.因为listiew在初始化完成的时候,OnScrollListener的onScrollStateChanged与onScroll并未被触发,如何初始化第一页的图片? package com.test.l

Android在ListView显示图片(重复错乱闪烁问题)

1.原因分析 ListView item缓存机制: 为了使得性能更优,ListView会缓存行item(某行对应的View). ListView通过adapter的getView函数获得每行的item. 滑动过程中 a. 如果某行item已经滑出屏幕,若该item不在缓存内,则put进缓存,否则更新缓存: b. 获取滑入屏幕的行item之前会先判断缓存中是否有可用的item,如果有,做为convertView参数传递给adapter的getView. 这样,如下的getView写法就可以充分利用

android listview异步加载图片错位,重复,闪烁分析以及解决方案

我们在使用listview异步加载图片 的时候,在快速滑动或者网络不好的情况下,会出现图片错位,重复,闪烁等问题,其实这些问题总结起来就是一个问题, 比如listview上有100个item,一屏只显示10个item,我们知道getView()中converView是用来复用view对象的,因为一个item的view对象,而imageview控件就是view通过findViewById()获得的,而我们在复用view对象时,也就是说这个imageview也被复用了,比如第11个item的view

Android ListView异步加载图片错位、重复、闪烁分析以及解决方案

我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而ImageView控件就是View对象通过findViewById()获得的,而我们在复用View对象时,同时这个Ima

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

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

android listview 异步加载图片并防止错位+双缓存

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

android listview 异步加载图片并防止错位 解决办法

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