universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法
在listview/gridview中使用UIL来display每个item的图片,当图片数量较多需要滑动滚动时会出现卡顿,而且加载过的图片再次上翻后依然会重复加载(显示设置好的加载中图片)
最近在使用UIL遇到了这个问题,相信这个问题许多使用UIL的人都碰到过
现在把解决方法贴出来给有同样问题的朋友做参考
先看下UIL的工作流程

在已经允许内存,存储卡缓存的前提下,当一个图片被请求display时,首先要判断图片是否缓存在内存中,如果false则尝试从存储卡读取,如果依然不存在最后才从网络地址下载
从内存读取的速度最快,存储卡次之,在我们滚动listview的时候,如果是从内存加载图片则会显得非常流畅,如果是存储卡就会先出现载入中图片然后再显示实际图片
我们通常认为已经读过一次的图片自然将会加入内存缓存中,那么下一次读取将是直接从内存中读取,但是实际上载入过的图片在滑动出屏幕再滑动回来后依然会再次从存储卡读取,这主要是UIL的缓存策略引起的一个"疑似BUG"
查看UIL的源码,displayImage函数
public void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {
displayImage(uri, new ImageViewAware(imageView), options, null, null);
}
会有ImageAware接口的一个实例化,这个默认的实例化有个重要的参数 :checkActualViewSize 具体说明如下
public ViewAware(View view) {
this(view, true);
}
/**
* Constructor
*
* @param view {@link android.view.View View} to work with
* @param checkActualViewSize <b>true</b> - then {@link #getWidth()} and {@link #getHeight()} will check actual
* size of View. It can cause known issues like
* <a href="https://github.com/nostra13/Android-Universal-Image-Loader/issues/376">this</a>.
* But it helps to save memory because memory cache keeps bitmaps of actual (less in
* general) size.
* <p/>
* <b>false</b> - then {@link #getWidth()} and {@link #getHeight()} will <b>NOT</b>
* consider actual size of View, just layout parameters. <br /> If you set 'false'
* it's recommended 'android:layout_width' and 'android:layout_height' (or
* 'android:maxWidth' and 'android:maxHeight') are set with concrete values. It helps to
* save memory.
*/
public ViewAware(View view, boolean checkActualViewSize) {
if (view == null) throw new IllegalArgumentException("view must not be null");
this.viewRef = new WeakReference<View>(view);
this.checkActualViewSize = checkActualViewSize;
}
这个参数会影响缓存时的key名称,当图片第一次缓存时,当时图片并未下载,自然无法获得图片的长宽尺寸,这时UIL会使用配置预设的maxwidth和maxheight为长宽,缓存的key名称为类似这样:url_widthxheight
在checkActualViewSize设置为true时,第二次载入图片的view将会读取view的长宽,这时的长宽会是图片的实际尺寸,相应的生成的缓存key名称也会变成url_realwidthxrealheight,这个名称同之前缓存的不同,因此也当然不能在缓存查询中命中
所以最后就需要再次从存储中加载图片,并以新的keyname再存一份副本到内存中
解决方法有两个:
1)设置imageview的layout_width和layout_height为实际图片长宽(假如你的图片都是固定尺寸的,这样做就OK了)
2)display的方法修改一下,不直接display imageview改为ImageAware,类似
ImageAware imageAware = new ImageViewAware(imageView, false);
imageLoader.displayImage(imageUri, imageAware);
显式的将checkActualViewSize设为false, 这样图片的缓存也将只会保存一个副本,保证第二次查询时可以直接命中
按上述方法设置之后一般来说在listview/gridview滑动时图片效果基本没什么大问题了,但是还有些额外设置也许也是大家需要注意的
首先是config的初始化
File cacheDir = StorageUtils.getOwnCacheDirectory(getApplicationContext(), "imageloader/Cache"); //缓存文件的存放地址
ImageLoaderConfiguration config = new ImageLoaderConfiguration
.Builder(getApplicationContext())
.memoryCacheExtraOptions(, ) // max width, max height
.threadPoolSize()//线程池内加载的数量
.threadPriority(Thread.NORM_PRIORITY - ) //降低线程的优先级保证主UI线程不受太大影响
.denyCacheImageMultipleSizesInMemory()
.memoryCache(new LruMemoryCache( * * )) //建议内存设在5-10M,可以有比较好的表现
.memoryCacheSize( * * )
.discCacheSize( * * )
.discCacheFileNameGenerator(new Md5FileNameGenerator())
.tasksProcessingOrder(QueueProcessingType.LIFO)
.discCacheFileCount() //缓存的文件数量
.discCache(new UnlimitedDiscCache(cacheDir))
.defaultDisplayImageOptions(DisplayImageOptions.createSimple())
.imageDownloader(new BaseImageDownloader(getApplicationContext(), * , * )) // connectTimeout (5 s), readTimeout (30 s)
.writeDebugLogs() // Remove for release app
.build();
然后是option的设置
options = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.default_cover)
.showImageForEmptyUri(R.drawable.default_cover)
.showImageOnFail(R.drawable.default_cover)
.cacheInMemory(true)
.cacheOnDisc(true)
.imageScaleType(ImageScaleType.NONE)
.bitmapConfig(Bitmap.Config.RGB_565)//设置为RGB565比起默认的ARGB_8888要节省大量的内存
.delayBeforeLoading()//载入图片前稍做延时可以提高整体滑动的流畅度
.build();
滑动时禁止加载也可以有效的提高表现
setOnScrollListener(new PauseOnScrollListener(imageLoader, true, true));//两个分别表示拖动下拉条和滑动过程中暂停加载
最后就是在getview中,例行的viewholder保存状态之外,将URL存入imageview的tag中,通过对比URL值来减少UIL的display次数以提高表现
UIL是个非常不错的图片加载类的第三方库,可以帮我们在开发过程中省不少事,不过如果想用好也需要自己真正的去研究下
参考资料:
https://github.com/nostra13/Android-Universal-Image-Loader/issues/376
https://github.com/nostra13/Android-Universal-Image-Loader/wiki/Task-flow
universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法
universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法的更多相关文章
- 史上最全的CSS hack方式一览 jQuery 图片轮播的代码分离 JQuery中的动画 C#中Trim()、TrimStart()、TrimEnd()的用法 marquee 标签的使用详情 js鼠标事件 js添加遮罩层 页面上通过地址栏传值时出现乱码的两种解决方法 ref和out的区别在c#中 总结
史上最全的CSS hack方式一览 2013年09月28日 15:57:08 阅读数:175473 做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我 ...
- Easyui中使用jquery或js动态添加元素时出现的样式失效的解决方法
Easyui中使用jquery或js动态添加元素时出现的样式失效的解决方法 2014-03-27 11:44:46| 分类: Easy UI|举报|字号 订阅 可以使用$.parser.pa ...
- log4j中Spring控制台输出Debug级信息过多解决方法
log4j中Spring控制台输出Debug级信息过多解决方法 >>>>>>>>>>>>>>>>> ...
- MySQL中遇到的几种报错及其解决方法
MySQL中遇到的几种报错及其解决方法 1.[Err] 1064 - You have an error in your SQL syntax; check the manual that corre ...
- Linux下Oracle中SqlPlus时上下左右键乱码问题的解决办法
window下的sqlplus可以通过箭头键,来回看历史命令,用起来非常的方便. 但是在Linux下,会出现各种乱码,非常不方便,如下图所示,每次打错一个字符就需要重新打一遍. 解决办法:rlwrap ...
- [datatable]关于在DataTable中执行DataTable.Select("条件")返回DataTable的解决方法
-- :09关于在DataTable中执行DataTable.Select("条件")返回DataTable的解决方法 在实际编程工程中,常常遇到这样的情况:DataTable并不 ...
- Eclipse中SVN修改的*星号没了,解决方法
Eclipse中SVN修改的*星号没了,解决方法 打开Preference 第一步:去掉外加的 ">" 第二步:勾选Outgoing changes 这样做之后," ...
- Python3中使用HTMLTestRunner报No module named 'StringIO'解决方法
今天在学习使用HTMLTestRunner生成测试报告时遇到一个报错,如图所示: 网上搜索了下“No module named 'StringIO'”解决方法,原来我用的是Python 3.X版本,而 ...
- 在MonoGame中SetRenderTarget会把后备缓冲区清除的解决方法
在MonoGame中SetRenderTarget会把后备缓冲区清除的解决方法: 在构造函数中添加事件:graphics.PreparingDeviceSettings += Graphics_Pre ...
随机推荐
- CF-Mr. Kitayuta's Colorful Graph
B. Mr. Kitayuta's Colorful Graph time limit per test 1 second memory limit per test 256 megabytes in ...
- [HNOI 2013] 消毒 (搜索,二分图匹配)
题目大意 一个a * b * c(a * b * c <= 5000)大小的长方体中有一些点需要被覆盖,每次可以选择任意大小的长方体,覆盖其中的点,产生的代价为这个长方体长宽高中最小的那个的长度 ...
- wpf在异步中给前台赋值
wpf,新建异步方法: Thread newThread = new Thread(new ParameterizedThreadStart(GetResult)); newThread.Start( ...
- effective C++: 5实现
五.实现 大多数情况下,适当提出拟的类定义以及函数声明,是花费最多心力的两件事.尽管如此,还是有很多东西需要小心:太快定义变量可能造成效率上的拖延:过度使用转型(casts)可能导致代码变慢又难维护, ...
- 对C++默认构造函数的理解
在文章开始之前,首先指出对于c++新手的两个常见的误解: 一.任何class如果没有定义default constructor,就会被合成出一个来. 二.编译器合成出来的default constru ...
- Android 监听wifi广播的两种方式
1.XML中声明 <receiver android:name=".NetworkConnectChangedReceiver" > <i ...
- 设计模式14---设计模式之命令模式(Command)(行为型)
1.场景模拟 请用软件模拟开机过程 按下启动按钮 然后电源供电 主板开始加电自检 BIOS依次寻找其他设备的BIOS并且让他们初始化自检 开始检测CPU,内存,光盘,硬盘,光驱,串口,并口,软驱即插即 ...
- html+jq实现简单的图片轮播
今天上班没事,就自己琢磨着写一下图片轮播,可是没想到,哈哈竟然写出来啦,下面就贴出来代码,作为纪念保存下下哈: <body style="text-align: center;&quo ...
- 服务 远程服务 AIDL 进程间通讯 IPC 深化
示例 aidl接口文件 package com.bqt.aidlservice.aidl; parcelable Person; package com.bqt.aidlservice.aidl; ...
- Access to the path '....' is denied.解决方法
昨天公司项目迁移服务器,从自己服务器迁移到阿里云服务器,部署完成后发现有一个页面要读取磁盘上的静态文件就报错了... 如图: 解决办法: 在 Web.Config 的 <System.Web&g ...