关于在RecyclerView中使用UniversalImageLoader加载图片刷新数据时...

9
回复
2240
查看
[复制链接]

2

主题

24

帖子

540

安币

代码手工艺人

Rank: 4

QQ
发表于 2017-11-8 16:33:16 | 显示全部楼层 |阅读模式

关于在RecyclerView中使用UniversalImageLoader加载图片刷新数据时引起的闪烁问题

这个是我在用RecyclerView借助了ItemTouchHelper的帮助下实现的一个拖拽效果。我在成功拖拽完毕后调用notifyDatasetChanged进行数据更新时出现了图片闪烁一下的情况。
然后就开始在网上找解决办法。最终都没有达到预期的效果,但也不是说网上的办法不行,在此,我总结除了一下几点:
1.如果不是用的UIL框架加载图片,而是采用原生的imageView.setImage的方式加载而在调用notifyDatasetChanged或者notifyItemRangeChanged(start,end)出现刷新整个数据时而产生的闪烁,这里可以归结于RecyclerView自身的因素。
解决办法:
(1)尽量给每个item设置单独的id,也就是在adapter中要setHasStableIds(true),然后在getItemId中返回你的item的id.谷歌首先是很推荐用户使用这个方法的,设置了id后还会解决position错位等很多莫名奇妙的问题。
(2)关闭RecyclerView的默认Item动画效果。

((DefaultItemAnimator)recyclerView.getAnimator()).setSupportsChangeAnimations(false);

上面的方法都能很好地解决自身因素产生地闪烁问题。

2.采用UIL框架产生的闪烁。
首先这个应该是UIL自己的加载机制而产生的问题。UIL可以有多级缓存加载。直接在绑定Viewholder的时候进行Display方法的显示,会在holder复用的时候不断调用多级加载的过程,一班来讲会由内存缓存到磁盘缓存的过渡。我没有具体研究过整个加载流程是怎样的,但是毫无疑问,和普通的imageView.setImage的方式比起来,要复杂得多。其实我在关闭内存缓存进行加载的时候,发现在刷新数据时,UIL先显示的是你在配置项里面的默认图片,然后才显示真正的图片,虽然时间比较短,但是过渡瞬间还是比较清除的。接着我开启了内存缓存,然后没有看见默认图片,而是闪烁一下。在这里,我可以大胆推测:
(1)内存缓存的加载速度远远大于磁盘缓存
(2)闪烁实际上也是进行了默认图片到真实图片的过渡,只不过,内存缓存加载的速度远远大于磁盘缓存,导致默认图片都没显示完就直接显示真实图片了,但是毕竟是过渡,还是有时间差了,所以产生了闪烁。

为此,为了验证我的猜想,特意写了下面的这个方法:

/**
     * 重定义UIL显示图片的方式<br>
     *     UIL可以有多级缓存,(内存缓存,磁盘缓存)。
     *     直接通过display方法显示图片,在一般的操作中是完全OK的。但是如果涉及到RecyclerView的数据全量更新,
     *     如{@link RecyclerView.Adapter#notifyDataSetChanged()}或者{@link android.support.v7.widget.RecyclerView.Adapter#notifyItemChanged(int)}
     *     之类的方法时,会闪烁。网上的说法很繁杂,有说是RecyclerView自带的item动画效果之类引起的等等。结果排查发现
     *     是UIL自身加载图片的机制引起的。这个方法可以解决闪烁的问题。
     * @param view
     * @param imgUrl
     * @param option
     */
    public void showImage(ImageView view, String imgUrl, DisplayImageOptions option){
        //确保当前的加载配置里面配置了内存缓存true
        Bitmap bmp= ImageLoader.getInstance().getMemoryCache().get(imgUrl);
        if(bmp!=null){
            view.setImageBitmap(bmp);
        }else{
            //确保当前的加载配置里面配置了磁盘缓存true
            File cache=ImageLoader.getInstance().getDiskCache().get(imgUrl);
            if(cache!=null){
                //这里根据具体地需要,可以自己定义Bitmap的压缩项,不过一般无需再次定制
                //UIL的初始配置就已经决定了压缩结果,效果还是比较好的,直接decode就行了
                view.setImageBitmap(BitmapFactory.decodeFile(cache.getAbsolutePath()));
            }else{
                //如果前面两项都没有,证明图片还没有被缓存过,老实地用传统方法加载吧
                ImageLoader.getInstance().displayImage(imgUrl,view, option);
            }
        }
    }

现在,再让我们来看看效果:
pictrue
完美,不再出现闪烁。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

62

主题

9758

帖子

912

安币

代码手工艺人

学海无涯

Rank: 4

QQ达人

发表于 2017-11-8 16:39:08 | 显示全部楼层
感谢分享,楼主V5~

7

主题

9564

帖子

1970

安币

Android大神

Rank: 6Rank: 6

发表于 2017-11-8 16:39:18 | 显示全部楼层
楼主是好人,回个帖会有安币吗?

6

主题

9492

帖子

2877

安币

Android大神

Rank: 6Rank: 6

发表于 2017-11-8 16:41:10 | 显示全部楼层
每次我都积极回帖的,想要安币~

11

主题

9403

帖子

982

安币

代码手工艺人

Rank: 4

发表于 2017-11-8 16:45:10 | 显示全部楼层
帮帮顶顶!!

0

主题

1万

帖子

2405

安币

Android大神

Rank: 6Rank: 6

发表于 2017-11-8 16:49:51 | 显示全部楼层
感觉楼主很用心,辛苦啦~

0

主题

9130

帖子

2380

安币

Android大神

Rank: 6Rank: 6

发表于 2017-11-8 16:55:14 | 显示全部楼层
楼主是好人,回个帖会有安币吗?

2

主题

24

帖子

540

安币

代码手工艺人

Rank: 4

QQ
 楼主| 发表于 2017-11-8 16:59:01 | 显示全部楼层
东西南北 发表于 2017-11-8 16:55
楼主是好人,回个帖会有安币吗?

不好意思,我是新号,没什么安币,发帖就是为了硬的安币
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

领先的中文移动开发者社区
18620764416
7*24全天服务
意见反馈:1294855032@qq.com

扫一扫关注我们

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粤ICP备15117877号 )