1:Item图片显示重复

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

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

3. Item图片显示闪烁

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

解决方案:

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

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

滑动过程中

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异步下载和convertView复用产生的错位问题的更多相关文章

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

    网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertVie ...

  2. Android ListView异步载入图片乱序问题,原因分析及解决方式

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/45586553 在Android全部系统自带的控件其中,ListView这个控件算是 ...

  3. 又优化了一下 Android ListView 异步加载图片

    写这篇文章并不是教大家怎么样用listview异步加载图片,因为这样的文章在网上已经有很多了,比如这位仁兄写的就很好: http://www.iteye.com/topic/685986 我也是因为看 ...

  4. android AsyncTask异步下载并更新进度条

    AsyncTask异步下载并更新进度条    //如果不是很明白请看上篇文章的异步下载 AsyncTask<String, Integer, String> 第一个参数:String 传入 ...

  5. android ListView异步加载图片(双缓存)

    首先声明,参考博客地址:http://www.iteye.com/topic/685986 对于ListView,相信很多人都很熟悉,因为确实太常见了,所以,做的用户体验更好,就成了我们的追求... ...

  6. Android Listview异步动态加载网络图片

    1.定义类MapListImageAndText管理ListViewItem中控件的内容 package com.google.zxing.client.android.AsyncLoadImage; ...

  7. 转:Android ListView 异步加载图片

    http://www.iteye.com/topic/1118828 http://www.iteye.com/topic/1127914 这样做无疑是非常可取的方法,但是加载图片时仍然会感觉到轻微的 ...

  8. Android ListView异步加载数据

    1.主Activity public class MainActivity extends Activity { private ListView listView; private ArrayLis ...

  9. Android的ListView异步加载图片时,错位、重复、闪烁问题的分析及解决方法

    Android ListView异步加载图片错位.重复.闪烁分析以及解决方案,具体问题分析以及解决方案请看下文. 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图 ...

随机推荐

  1. Dubbo框架应用之(一)--服务体系

    Dubbo 是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 Spring框架无缝集成,也是一个非常全面的SOA基础框架.其是阿里巴巴SO ...

  2. 理解性能的奥秘——应用程序中慢,SSMS中快(1)——简介

    本文属于<理解性能的奥秘--应用程序中慢,SSMS中快>系列 在工作中发现有不少类似的现象,有幸看到国外大牛写的一篇文章,由于已经完善得不能再添油加醋,所以决定直接翻译,原文出处:http ...

  3. Linux 环境下一些常用命令(四)

    转自 http://www.oschina.net/translate/20-advanced-commands-for-middle-level-linux-users 31. 命令: rm 'rm ...

  4. ACE在Linux下编译安装

    下载地址: http://download.dre.vanderbilt.edu/ ACE版本:ACE-6.2.2.tar.bz2 下载完成后解压路径为:/root/ACE/ACE_wrappers ...

  5. Hadoop:Hadoop单机伪分布式的安装和配置

    http://blog.csdn.net/pipisorry/article/details/51623195 因为lz的linux系统已经安装好了很多开发环境,可能下面的步骤有遗漏. 之前是在doc ...

  6. Swift基础之init方法,实例方法,类方法(静态方法)的使用(多标签Demo)

    Xcode更新过后,有些方法都进行了改变,Demo中有变化的都进行了简单的标记,具体以后遇见再说 创建一个UIView类,用init方法创建两种类型,显示多标签,创建静态方法进行调用,创建类方法进行调 ...

  7. testng的使用

    TestNG教程 TestNG是一个测试框架,其灵感来自JUnit和NUnit,但同时引入了一些新的功能,使其功能更强大,使用更方便. TestNG设计涵盖所有类型的测试:单元,功能,端到端,集成等, ...

  8. JVM学习之-栈

    JVM栈解决程序的运行问题,即程序如何执行,或者说如何处理数据;JVM堆解决的是数据存储的问题,即数据怎么放.放在哪儿,另外JVM堆中存的是对象.JVM栈中存的是基本数据类型和JVM堆中对象的引用. ...

  9. IIS部署WCF报 无法读取配置节“protocolMapping”,因为它缺少节声明

    今天写了个wcf的测试程序放在客户的服务器上供他们测试调用,部署到IIS后浏览报错了,根据错误的提示看出似乎是识别不了这个节点名,偶然的去看了下进程池中该站点的进程池名字的高级设置,看到使用的.net ...

  10. 如何使用excel画甘特图

    甘特图小伙伴们都非常的熟悉,首先小编简单的向各位小伙伴介绍一下什么是甘特图,甘特图内在思想简单,即以图示的方式通过活动列表和时间刻度形象地表示出任何特定项目的活动顺序与持续时间.基本是一条线条图,横轴 ...