博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案
阅读量:6652 次
发布时间:2019-06-25

本文共 4638 字,大约阅读时间需要 15 分钟。

在Android所有系统自带的控件当中,ListView这个控件算是用法比较复杂的了,关键是用法复杂也就算了,它还经常会出现一些稀奇古怪的问题,让人非常头疼,下面通过本篇文章给大家分享Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案,需要朋友可以参考。

Android ListView异步加载图片错位、重复、闪烁分析以及解决方案,具体问题分析以及解决方案请看下文。

我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位、重复、闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化。

比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而ImageView控件就是View对象通过findViewById()获得的,而我们在复用View对象时,同时这个ImageView对象也被复用了。比如第11个Item的View复用了第1个Item View对象,那么ImageView就同时被复用了,所以当图片没下载出来,这个ImageView(第11个Item)显示的数据就是复用(第1个Item)的数据。

1:Item图片显示重复

这个显示重复是指当前行Item显示了之前某行Item的图片。

比如ListView滑动到第2行会异步加载某个图片,但是加载很慢,加载过程中ListView已经滑动到了第14行,且滑动过程中该图片加载结束。第2行已不在屏幕内,根据上面介绍的缓存原理,第2行的View对象可能被第14行复用,这样我们看到的就是第14行显示了本该属于第2行的图片,造成显示重复。

2. Item图片显示错乱

这个显示错乱是指某行Item显示了不属于该行Item的图片。

跟上面的原因一样。

3. Item图片显示闪烁

上面介绍的另外一种情况,如果第14行图片又很快加载结束,所以我们看到第14行先显示了复用的第2行的图片,立马又显示了自己的图片进行覆盖造成闪烁错乱。

解决方案:

通过上面的分析我们知道了出现错乱的原因是异步加载及对象被复用造成的,如果每次getView能给对象一个标识,在异步加载完成时比较标识与当前行Item的标识是否一致,一致则显示,否则不做处理即可。

原理:首先给ImageView设置一个Tag,这个Tag中设置的是图片的url,然后在加载的时候取得这个url和要加载那position中的url对比,如果不相同就加载,相同就是复用以前的就不加载了。

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

1、原因分析

ListView item缓存机制:

为了使得性能更优,ListView会缓存行item(某行对应的View)。

ListView通过adapter的getView函数获得每行的item。

滑动过程中

a. 如果某行item已经滑出屏幕,若该item不在缓存内,则put进缓存,否则更新缓存;

b. 获取滑入屏幕的行item之前会先判断缓存中是否有可用的item,如果有,做为convertView参数传递给adapter的getView。

这样,如下的getView写法就可以充分利用缓存大大提升ListView的性能。即便上万个行item,最多inflate的次数为n,

n为一屏最多显示ListView 行item的个数。

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的标识是否一致,一致则显示,否则不做处理即可。

andbase中的实现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
  
* 显示这个图片,解决了列表问题.
  
* 列表问题:滑动过程中,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);
   
}
  
}

以上内容就是Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案,希望对大家今后的工作和学习有所帮助。

转载于:https://www.cnblogs.com/xieping/p/4784535.html

你可能感兴趣的文章
无聊领养一个QQ宠物
查看>>
FastText 文本分类使用心得
查看>>
电子表单系列谈之纯文本辅助设计表单
查看>>
全营销:聚集三大媒体营销正能量
查看>>
《方寸指间——移动设计实战手册》
查看>>
HDU 4400 Mines(STL)
查看>>
Regular expression notation(正则表达式)
查看>>
SQL Server 2005 Hierarchies WITH Common Table Expressions
查看>>
艾伟_转载:二十行C#代码打造Ruby Markup Builder
查看>>
一起谈.NET技术,SharePoint 2010 BI:Chart WebPart
查看>>
一起谈.NET技术,C#特性Attribute的实际应用之:代码统计分析
查看>>
2010年度最有技术含量攻击:Padding Oracle Attack
查看>>
selenium处理select标签的下拉框
查看>>
Radio/Check混合MFC树控件实现
查看>>
ASIHTTPReques用法
查看>>
照相机滤镜使用,优化解码和滤镜导致的预览卡屏现象
查看>>
第一个JAVA SE项目(神马博彩)经验总结
查看>>
(android插件)获取jar包中的资源总结
查看>>
Grunt(页面静态引入的文件地址的改变探究)-V2.0
查看>>
函数之关键参数
查看>>