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


    最新内容建议直接访问原文:Android ListView滑动过程中图片显示重复错乱闪烁问题解决

    主要分析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的个数。

    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中添加

    @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表示设置标识,方便下面进行标志比对

    在ImageCache的OnImageCallbackListener的onImageLoaded函数中添加

    public void onImageLoaded(String imageUrl, Drawable imageDrawable, View view, boolean isInCache) {
        // 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);
            }
        }
    };

    在上面用String imageUrlTag = (String)imageView.getTag();取得之前设置的tag,然后和当前的url进行比较,如果相等则显示,解决了b. 行item图片显示错乱,c. 行item图片显示错乱的两个问题。其中ObjectUtils可见ObjectUtils@Github.

    其他异步加载过程解决原理类似。

    你可能还感兴趣:

    Android ImageCache图片缓存

    下拉刷新及滚动到底部加载更多的Listview使用

    Android公共库(缓存 下拉ListView 下载管理Pro 静默安装 root运行 Java公共类)

    Android系统下载管理DownloadManager功能介绍及使用示例

  • 相关阅读:
    D11 列表 list 元祖 字典dict
    D10 基本数据类型(各种职业的技能分析) 主要为 int 和 str
    Python D9 学习
    面向对象方法传参实现数组求和,求平均值
    用带参数的方法给空数组放元素,寻找数组里面的值是否存在。
    两种方法把类和对象写在同一个文件内
    创建一个管理员对象,输入正确用户名和密码,可以修改密码(类和对象分为两个文件,区别于放在一个文件内)
    创建一个游客对象,输入信息判断游客年龄是否免费游览
    建立一个学生对象,输出学生信息
    把输入的数字转为数组,拿出其中的最小值
  • 原文地址:https://www.cnblogs.com/trinea/p/3244741.html
Copyright © 2020-2023  润新知