在手机上尤其需要考虑网络对图片下载的影响,常见的情况是在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图片下载技巧的更多相关文章

  1. android universal image loader 缓冲原理详解

    1. 功能介绍 1.1 Android Universal Image Loader Android Universal Image Loader 是一个强大的.可高度定制的图片缓存,本文简称为UIL ...

  2. android开源项目:图片下载缓存库picasso

    picasso是Square公司开源的一个Android图形缓存库,地址http://square.github.io/picasso/,可以实现图片下载和缓存功能. picasso有如下特性: 在a ...

  3. MonkeyRunner源代码分析Android通信设备

    正如前面<谁动了我的截图?--Monkeyrunner takeSnapshot方法源代码跟踪分析>所述,本文主要会尝试描写叙述android的自己主动化測试框架MonkeyRunner到 ...

  4. 结合源代码分析android的消息机制

    描写叙述 结合几个问题去看源代码. 1.Handler, MessageQueue, Message, Looper, LocalThread这5者在android的消息传递过程中扮演了什么样的角色? ...

  5. Android Universal Image Loader java.io.FileNotFoundException: http:/xxx/lxx/xxxx.jpg

    前段时间在使用ImageLoader异步加载服务端返回的图片时总是出现 java.io.FileNotFoundException: http://xxxx/l046/10046137034b1c0d ...

  6. android源代码分析 android toast使用具体解释 toast自己定义

    在安卓开发过程中.toast使我们常常使用的一个类.当我们须要向用户传达一些信息,可是不须要和用户交互时,该方式就是一种十分恰当的途径. 我们习惯了这样使用toast:Toast.makeText(C ...

  7. Android性能优化-减小图片下载大小

    原文链接 https://developer.android.com/topic/performance/network-xfer.html 内容概要 理解图片的格式 PNG JPG WebP 如何选 ...

  8. Android KLog源代码分析

    Android KLog源代码分析 Android KLog源代码分析 代码结构 详细分析 BaseLog FileLog JsonLog XmlLog 核心文件KLogjava分析 遇到的问题 一直 ...

  9. 从Handler+Message+Looper源代码带你分析Android系统的消息处理机制

    PS一句:不得不说CSDN同步做的非常烂.还得我花了近1个小时恢复这篇博客. 引言 [转载请注明出处:http://blog.csdn.net/feiduclear_up CSDN 废墟的树] 作为A ...

随机推荐

  1. IE 下JS和CSS 阻塞后面内容总结

    总结: 1.  CSS 都是可以并行下载的. 2.  IE6 和 IE7   JS 不能并行下载,CSS 和 JS 阻塞后面内容下载. 3.  IE8   JS 还是会阻塞图片下载 开始改变加载模式, ...

  2. ntc 热敏电阻

    来自维基百科  http://zh.wikipedia.org/zh/%E7%83%AD%E6%95%8F%E7%94%B5%E9%98%BB 热敏电阻的电阻值是根据温度由公式计算而来的,知道这一点就 ...

  3. MS sql server 基础知识回顾(二)-表连接和子查询

    五.表连接 当数据表中存在许多重复的冗余信息时,就要考虑将这些信息建在另一张新表中,在新表中为原表设置好外键,在进行数据查询的时候,就要使用到连接了,表连接就好像两根线,线的两端分别连接两张表的不同字 ...

  4. 现成的HTML5框架

    1>sencha-touch 2>phoneGap 3>jQuery mobile 4>bootstrap

  5. 我所了解的 京东、携程、eBay、小米 的 OpenStack 云

    参加过几次 OpenStack meetup 活动,听过这几家公司的Architect 讲他们公司的 OpenStack产品.本文试着凭借影响加网络搜索,按照自己的理解,对这些公司的 OpenStac ...

  6. Windows 下, SetTimer 定时器的研究.

    一直很困惑一个问题: 我设置了一个10秒的定时器,可是被调用的函数要花费30秒, 那待调用的函数第二次是什么时候调用的呢? 20秒, 40秒, 还是50秒呢.... 所以我进行了实验. 我写了一个类  ...

  7. display 显示隐藏 ESAYuI

    $("#rejectCauseDisplay").css('display',"block");     $("#rejectCauseDisplay ...

  8. .Net中几种常见的页面跳转传值方法

    1.ASP Server对象Execute方法 ASP Server对象的Execute方法可以在执行当前页面的过程中将另一个页面执行结果的内容插入到当前页面的输出中.Execute方法带一个参数,是 ...

  9. jquery实现div遮罩层

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. matlab微分方程dsolve使用

    y=dsolve('Dy=exp(-x-y-2)','y(0)=-2','x') dy/dx 写成Dy (注意大小写) y(0)=-2 表示初始条件 'x'表示积分变量