从源代码分析Android-Universal-Image-Loader图片下载技巧
在手机上尤其需要考虑网络对图片下载的影响,常见的情况是在2G网络、在3G网络需要不同的下载策略,也就是说在慢速网络与快速网络中下载需要考虑不同的策略。一种常见的策略就是Android客户端和服务端相配合的方式,针对慢速网络对图片进行优化(让图片的质量低一点,保证能下载),但是这种情况不在本文讨论的范围中。在本文中主要讨论针对不能改变的服务器图片质量(图片的大小 xx KB),Android-Universal-Image-Loader所采取的下载策略。
需要具体考虑网络情况有:快速、慢速、无网络权限。针对这三种情况,在UIL中分别定义了三种策略。还是让我们从代码入手看看。在《从代码分析Android-Universal-Image-Loader的图片加载、显示流程》我们分析了图片的下载是从LoadAndDisplayImageTask.decodeImage(…)中开始的,其中函数内部调用了getDownloader(),然后在ImageDecoder接口的实现类(BaseImageDecoder)中获取InputStream实现图片的下载和解析。跟进去getDownloader()中看看。
private ImageDownloader getDownloader() {
ImageDownloader d;
if (engine.isNetworkDenied()) {
d = networkDeniedDownloader;
} else if (engine.isSlowNetwork()) {
d = slowNetworkDownloader;
} else {
d = downloader;
}
return d;
}
networkDeniedDownloader、slowNetworkDownloader、downloader究竟是什么?在LoadAndDisplayImageTask的构造函数中我们看到他们实际是来源于ImageLoaderConfiguration类中对应的networkDeniedDownloader、slowNetworkDownloader、downloader。在ImageLoaderConfiguration的构造函数总,我们发现downloader来源于ImageLoaderConfiguration.Builder,分析后发现它就是一个BaseImageDownloader对象(最后在DefaultConfigurationFactory.createImageDownloade(…)中被初始化)。回到ImageLoaderConfiguration类的构造函数中(如下所示)
private ImageLoaderConfiguration(final Builder builder) {
resources = builder.context.getResources();
maxImageWidthForMemoryCache = builder.maxImageWidthForMemoryCache;
maxImageHeightForMemoryCache = builder.maxImageHeightForMemoryCache;
maxImageWidthForDiskCache = builder.maxImageWidthForDiskCache;
maxImageHeightForDiskCache = builder.maxImageHeightForDiskCache;
processorForDiskCache = builder.processorForDiskCache;
taskExecutor = builder.taskExecutor;
taskExecutorForCachedImages = builder.taskExecutorForCachedImages;
threadPoolSize = builder.threadPoolSize;
threadPriority = builder.threadPriority;
tasksProcessingType = builder.tasksProcessingType;
diskCache = builder.diskCache;
memoryCache = builder.memoryCache;
defaultDisplayImageOptions = builder.defaultDisplayImageOptions;
downloader
=
builder.downloader;
decoder = builder.decoder; customExecutor = builder.customExecutor;
customExecutorForCachedImages = builder.customExecutorForCachedImages; networkDeniedDownloader
= new NetworkDeniedImageDownloader(downloader); slowNetworkDownloader = new
SlowNetworkImageDownloader(downloader); L.writeDebugLogs(builder.writeLogs);
}
我们发现networkDeniedDownloader、slowNetworkDownloader都依赖与downloader对象,猜想这两个类应该是对BaseImageDownloader的一个包装。下面我们贴出NetworkDeniedImageDownloader、SlowNetworkImageDownloader的代码(它们在com.nostra13.universalimageloader.core.ImageLoaderConfiguration类中)
/**
* Decorator. Prevents downloads from network (throws {@link IllegalStateException exception}).<br />
* In most cases this downloader shouldn't be used directly.
*
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
* @since 1.8.0
*/
private static class NetworkDeniedImageDownloader implements ImageDownloader { private final ImageDownloader wrappedDownloader; public NetworkDeniedImageDownloader(ImageDownloader wrappedDownloader) {
this.wrappedDownloader = wrappedDownloader;
} @Override
public InputStream getStream(String imageUri, Object extra) throws IOException {
switch (Scheme.ofUri(imageUri)) {
case HTTP:
case HTTPS:
throw new IllegalStateException();
default:
return wrappedDownloader.getStream(imageUri, extra);
}
}
} /**
* Decorator. Handles <a href="http://code.google.com/p/android/issues/detail?id=6066">this problem</a> on slow networks
* using {@link com.nostra13.universalimageloader.core.assist.FlushedInputStream}.
*
* @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
* @since 1.8.1
*/
private static class SlowNetworkImageDownloader implements ImageDownloader { private final ImageDownloader wrappedDownloader; public SlowNetworkImageDownloader(ImageDownloader wrappedDownloader) {
this.wrappedDownloader = wrappedDownloader;
} @Override
public InputStream getStream(String imageUri, Object extra) throws IOException {
InputStream imageStream = wrappedDownloader.getStream(imageUri, extra);
switch (Scheme.ofUri(imageUri)) {
case HTTP:
case HTTPS:
return new FlushedInputStream(imageStream);
default:
return imageStream;
}
}
}
先看到NetworkDeniedImageDownloader类,这个类中由于对应的是没有网络访问权限(android.permission.INTERNET)的情况,这种情况下Http和Https自然就不能使用了,其他情况(如从本地资源中获取图片)还是可以的。NetworkDeniedImageDownloader.wrappedDownloader对象是什么呢?其实就是我们刚刚ImageLoaderConfiguration构造函数中传入的BaseImageDownloader对象。在看看这个类中的getStream(…)方法。
@Override
public InputStream getStream(String imageUri, Object extra) throws IOException {
switch (Scheme.ofUri(imageUri)) {
case HTTP:
case HTTPS:
return getStreamFromNetwork(imageUri, extra);
case FILE:
return getStreamFromFile(imageUri, extra);
case CONTENT:
return getStreamFromContent(imageUri, extra);
case ASSETS:
return getStreamFromAssets(imageUri, extra);
case DRAWABLE:
return getStreamFromDrawable(imageUri, extra);
case UNKNOWN:
default:
return getStreamFromOtherSource(imageUri, extra);
}
}
从这个函数中,我们可以看到UIL通过Scheme.ofUri(…)分析imageUri,根据ImageUri的类型选择对应的方法进行处理。通过分析Scheme类,我们发现UIL支持以下几种图片获取方式HTTP, HTTPS, FILE, CONTENT, ASSETS, DRAWABLE。
接下来,我们分析一下SlowNetworkImageDownloader.getStream(…)方法,每一次图片的下载最终都会通过BitmapFactory.decodeStream解析成Bitmap,供ImageView显示
。我们可以发现这个方法针对慢速网络使用FlushedInputStream来处理。使用这个类的原因是因为在慢速网络中,BitmapFactory.decodeStream无法正确解析完整的图片。具体的可以参考StackOverFlow上的帖子《
BitmapFactory.decodeStream always returns null and skia decoder shows decode returned false》和一个Google上的Bug 报告《BitmapFactory.decodeStream() fails if InputStream.skip() does not skip fully》。
网速不慢的下载就直接使用BaseImageDownloader.getStream(…)方法了。
至此,我们已经分析了UIL中图片下载技巧,最后梳理一下。为了应对慢速、正常、访问受限网络,UIL分别 使用了SlowNetworkDownloader、BaseImageLoader、NetworkDeniedDownloader来应对这些策略,在LoadAndDisplayImageTask.getDownloader(…)中通过获取对应的downloader,最后通过LoadAndDisplayImageTask.decodeImage(…)将图片解析出来。
从源代码分析Android-Universal-Image-Loader图片下载技巧的更多相关文章
- android universal image loader 缓冲原理详解
1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的.可高度定制的图片缓存,本文简称为UIL ...
- android开源项目:图片下载缓存库picasso
picasso是Square公司开源的一个Android图形缓存库,地址http://square.github.io/picasso/,可以实现图片下载和缓存功能. picasso有如下特性: 在a ...
- MonkeyRunner源代码分析Android通信设备
正如前面<谁动了我的截图?--Monkeyrunner takeSnapshot方法源代码跟踪分析>所述,本文主要会尝试描写叙述android的自己主动化測试框架MonkeyRunner到 ...
- 结合源代码分析android的消息机制
描写叙述 结合几个问题去看源代码. 1.Handler, MessageQueue, Message, Looper, LocalThread这5者在android的消息传递过程中扮演了什么样的角色? ...
- Android Universal Image Loader java.io.FileNotFoundException: http:/xxx/lxx/xxxx.jpg
前段时间在使用ImageLoader异步加载服务端返回的图片时总是出现 java.io.FileNotFoundException: http://xxxx/l046/10046137034b1c0d ...
- android源代码分析 android toast使用具体解释 toast自己定义
在安卓开发过程中.toast使我们常常使用的一个类.当我们须要向用户传达一些信息,可是不须要和用户交互时,该方式就是一种十分恰当的途径. 我们习惯了这样使用toast:Toast.makeText(C ...
- Android性能优化-减小图片下载大小
原文链接 https://developer.android.com/topic/performance/network-xfer.html 内容概要 理解图片的格式 PNG JPG WebP 如何选 ...
- Android KLog源代码分析
Android KLog源代码分析 Android KLog源代码分析 代码结构 详细分析 BaseLog FileLog JsonLog XmlLog 核心文件KLogjava分析 遇到的问题 一直 ...
- 从Handler+Message+Looper源代码带你分析Android系统的消息处理机制
PS一句:不得不说CSDN同步做的非常烂.还得我花了近1个小时恢复这篇博客. 引言 [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 作为A ...
随机推荐
- I/O阻塞非阻塞,同步异步
http://www.cnblogs.com/luotianshuai/p/5098408.html "阻塞"与"非阻塞"与"同步"与&qu ...
- dubbo 使用总结
第一步: 安装注册中心Register,这里选择 zookeeper 1.zookeeper下载url:http://zookeeper.apache.org; 2.下载解压完后如下: 3.将zoo_ ...
- jqeury datatable
1.自定义列信息 "aoColumnDefs":[ { ...
- ca des key crt scr
openssl genrsa -des3 -out domain.key 1024 openssl req -new -key domain.key -out domain.csr openssl r ...
- SQLServer2008R2 mdf文件还原数据库
偶然遇到要用mdf文件restore数据库,试了2个小时才弄出来,百度查出来的我试了都不太好用,或者是我没理解. 下面把我用的记录一下,以防忘记. 工具:SQLServer 2008R2 步骤: 1. ...
- sp_MSforeachtable使用方法
1)说明系统存储过程sp_MSforeachtable和sp_MSforeachdb,是微软提供的两个不公开的存储过程,从ms sql 6.5开始.存放在SQL Server的MASTER数据库中. ...
- Selenium2+python自动化7-xpath定位
前言 在上一篇简单的介绍了用工具查看目标元素的xpath地址,工具查看比较死板,不够灵活,有时候直接复制粘贴会定位不到.这个时候就需要自己手动的去写xpath了,这一篇详细讲解xpath的一些语法. ...
- Tableview的更新和删除某一行
.tableView的刷新 > 数据刷新的总体步骤 * 修改模型数据 * 刷新表格(刷新界面) > 刷新表格(刷新界面)的方法 * 全局刷新(每一行都会重新刷新) - (void)relo ...
- 如何编译Less
什么是LESS LESSCSS是一种动态样式语言,属于CSS预处理语言的一种.它编译后就是CSS了,大名鼎鼎的前端框架BootStrap就是用这个语言写的 下面示范下怎么用LESS编译成CSS,尽量简 ...
- setAttribute()和getAttibute(),getParameter()
request.setAttribute("key",value)方法给主键设置一个值, request.getAttribute("key")方法从上述设置的 ...