文档章节

Android Universal Image Loader 源码分析(五)

k
 kim366
发布于 2016/05/13 19:15
字数 2645
阅读 1
收藏 0
4.2.41 UnlimitedDiskCache.java

一个无大小限制的本地图片缓存。与BaseDiskCache无异,只是用了个意思明确的类名。

4.2.42 DiskLruCache.java

限制总字节大小的内存缓存,会在缓存满时优先删除最近最少使用的元素。

通过缓存目录下名为journal的文件记录缓存的所有操作,并在缓存open时读取journal的文件内容存储到LinkedHashMap<String, Entry> lruEntries中,后面get(String key)获取缓存内容时,会先从lruEntries中得到图片文件名返回文件。

LRU 的实现跟上面内存缓存类似,lruEntriesnew LinkedHashMap<String, Entry>(0, 0.75f, true),LinkedHashMap 第三个参数表示是否需要根据访问顺序(accessOrder)排序,true 表示根据accessOrder排序,最近访问的跟最新加入的一样放到最后面,false 表示根据插入顺序排序。这里为 true 且缓存满时trimToSize()函数始终删除第一个元素,即始终删除最近最少访问的文件。

来源于 JakeWharton 的开源项目 DiskLruCache,具体分析请等待 DiskLruCache 源码解析 完成。

4.2.43 LruDiskCache.java

限制总字节大小的内存缓存,会在缓存满时优先删除最近最少使用的元素,实现了DiskCache
内部有个DiskLruCache cache属性,缓存的存、取操作基本都是由该属性代理完成。

4.2.44 StrictLineReader.java

通过readLine()函数从InputStream中读取一行,目前仅用于磁盘缓存操作记录文件journal的解析。

4.2.45 Util.java

工具类。
String readFully(Reader reader)读取 reader 中内容。
deleteContents(File dir)递归删除文件夹内容。

4.2.46 ContentLengthInputStream.java

InputStream的装饰者,可通过available()函数得到 InputStream 对应数据源的长度(总字节数)。主要用于计算文件存储进度即图片下载进度时的总进度。

4.2.47 FailReason.java

图片下载及显示时的错误原因,目前包括:
IO_ERROR 网络连接或是磁盘存储错误。
DECODING_ERROR decode image 为 Bitmap 时错误。
NETWORK_DENIED 当图片不在缓存中,且设置不允许访问网络时的错误。
OUT_OF_MEMORY 内存溢出错误。
UNKNOWN 未知错误。

4.2.48 FlushedInputStream.java

为了解决早期 Android 版本BitmapFactory.decodeStream(…)在慢网络情况下 decode image 异常的 Bug。
主要通过重写FilterInputStream的 skip(long n) 函数解决,确保 skip(long n) 始终跳过了 n 个字节。如果返回结果即跳过的字节数小于 n,则不断循环直到 skip(long n) 跳过 n 字节或到达文件尾。

4.2.49 ImageScaleType.java

Image 的缩放类型,目前包括:
NONE不缩放。
NONE_SAFE根据需要以整数倍缩小图片,使得其尺寸不超过 Texture 可接受最大尺寸。
IN_SAMPLE_POWER_OF_2根据需要以 2 的 n 次幂缩小图片,使其尺寸不超过目标大小,比较快的缩小方式。
IN_SAMPLE_INT根据需要以整数倍缩小图片,使其尺寸不超过目标大小。
EXACTLY根据需要缩小图片到宽或高有一个与目标尺寸一致。
EXACTLY_STRETCHED根据需要缩放图片到宽或高有一个与目标尺寸一致。

4.2.50 ViewScaleType.java

ImageAware的 ScaleType。
将 ImageView 的 ScaleType 简化为两种FIT_INSIDECROP两种。FIT_INSIDE表示将图片缩放到至少宽度和高度有一个小于等于 View 的对应尺寸,CROP表示将图片缩放到宽度和高度都大于等于 View 的对应尺寸。

4.2.51 ImageSize.java

表示图片宽高的类。
scaleDown(…) 等比缩小宽高。
scale(…) 等比放大宽高。

4.2.52 LoadedFrom.java

图片来源枚举类,包括网络、磁盘缓存、内存缓存。

4.2.53 ImageDecoder.java

将图片转换为 Bitmap 的接口,抽象函数:

Bitmap decode(ImageDecodingInfo imageDecodingInfo) throws IOException;

表示根据ImageDecodingInfo信息得到图片并根据参数将其转换为 Bitmap。

4.2.54 BaseImageDecoder.java

实现了ImageDecoder。调用ImageDownloader获取图片,然后根据ImageDecodingInfo或图片 Exif 信息处理图片转换为 Bitmap。

主要函数:

(1). decode(ImageDecodingInfo decodingInfo)

调用ImageDownloader获取图片,再调用defineImageSizeAndRotation(…)函数得到图片的相关信息,调用prepareDecodingOptions(…)得到图片缩放的比例,调用BitmapFactory.decodeStream将 InputStream 转换为 Bitmap,最后调用considerExactScaleAndOrientatiton(…)根据参数将图片放大、翻转、旋转为合适的样子返回。

(2). defineImageSizeAndRotation(InputStream imageStream, ImageDecodingInfo decodingInfo)

得到图片真实大小以及 Exif 信息(设置考虑 Exif 的条件下)。

(3). defineExifOrientation(String imageUri)

得到图片 Exif 信息中的翻转以及旋转角度信息。

(4). prepareDecodingOptions(ImageSize imageSize, ImageDecodingInfo decodingInfo)

得到图片缩放的比例。

  1. 如果scaleType等于ImageScaleType.NONE,则缩放比例为 1;
  2. 如果scaleType等于ImageScaleType.NONE_SAFE,则缩放比例为 (int)Math.ceil(Math.max((float)srcWidth / maxWidth, (float)srcHeight / maxHeight))
  3. 否则,调用ImageSizeUtils.computeImageSampleSize(…)计算缩放比例。
    在 computeImageSampleSize(…) 中
  4. 如果viewScaleType等于ViewScaleType.FIT_INSIDE
    1.1 如果scaleType等于ImageScaleType.IN_SAMPLE_POWER_OF_2,则缩放比例从 1 开始不断 *2 直到宽或高小于最大尺寸;
    1.2 否则取宽和高分别与最大尺寸比例中较大值,即Math.max(srcWidth / targetWidth, srcHeight / targetHeight)
  5. 如果scaleType等于ViewScaleType.CROP
    2.1 如果scaleType等于ImageScaleType.IN_SAMPLE_POWER_OF_2,则缩放比例从 1 开始不断 *2 直到宽和高都小于最大尺寸。
    2.2 否则取宽和高分别与最大尺寸比例中较小值,即Math.min(srcWidth / targetWidth, srcHeight / targetHeight)
  6. 最后判断宽和高是否超过最大值,如果是 *2 或是 +1 缩放。
(5). considerExactScaleAndOrientatiton(Bitmap subsampledBitmap, ImageDecodingInfo decodingInfo, int rotation, boolean flipHorizontal)

根据参数将图片放大、翻转、旋转为合适的样子返回。

4.2.55 ImageDecodingInfo.java

Image Decode 需要的信息。
String imageKey 图片。
String imageUri 图片 uri,可能是缓存文件的 uri。
String originalImageUri 图片原 uri。
ImageSize targetSize 图片的显示尺寸。
imageScaleType 图片的 ScaleType。
ImageDownloader downloader 图片的下载器。
Object extraForDownloader 下载器需要的辅助信息。
boolean considerExifParams 是否需要考虑图片 Exif 信息。
Options decodingOptions 图片的解码信息,为 BitmapFactory.Options。

4.2.56 BitmapDisplayer.java

ImageAware中显示 bitmap 对象的接口。可在实现中对 bitmap 做一些额外处理,比如加圆角、动画效果。

4.2.57 FadeInBitmapDisplayer.java

图片淡入方式显示在ImageAware中,实现了BitmapDisplayer接口。

4.2.58 RoundedBitmapDisplayer.java

为图片添加圆角显示在ImageAware中,实现了BitmapDisplayer接口。主要通过BitmapShader实现。

4.2.59 RoundedVignetteBitmapDisplayer.java

为图片添加渐变效果的圆角显示在ImageAware中,实现了BitmapDisplayer接口。主要通过RadialGradient实现。

4.2.60 SimpleBitmapDisplayer.java

直接将图片显示在ImageAware中,实现了BitmapDisplayer接口。

4.2.61 BitmapProcessor.java

图片处理接口。可用于对图片预处理(Pre-process Bitmap)和后处理(Post-process Bitmap)。抽象函数:

public interface BitmapProcessor {
    Bitmap process(Bitmap bitmap);
}

用户可以根据自己需求去实现它。比如你想要为你的图片添加一个水印,那么可以自己去实现 BitmapProcessor 接口,在DisplayImageOptions中配置 Pre-process 阶段预处理图片,这样设置后存储在文件系统以及内存缓存中的图片都是加了水印后的。如果只希望在显示时改变不动原图片,可以在BitmapDisplayer中处理。

4.2.62 PauseOnScrollListener.java

可在 View 滚动过程中暂停图片加载的 Listener,实现了 OnScrollListener 接口。
它的好处是防止滚动中不必要的图片加载,比如快速滚动不希望滚动中的图片加载。在 ListView 或 GridView 中 item 加载图片最好使用它,简单的一行代码:

gridView.setOnScrollListener(new PauseOnScrollListener(ImageLoader.getInstance(), false, true));

主要的成员变量:
pauseOnScroll 触摸滑动(手指依然在屏幕上)过程中是否暂停图片加载。
pauseOnFling 甩指滚动(手指已离开屏幕)过程中是否暂停图片加载。
externalListener 自定义的 OnScrollListener 接口,适用于 View 原来就有自定义 OnScrollListener 情况设置。

实现原理:
重写onScrollStateChanged(…)函数判断不同的状态下暂停或继续图片加载。
OnScrollListener.SCROLL_STATE_IDLE表示 View 处于空闲状态,没有在滚动,这时候会加载图片。
OnScrollListener.SCROLL_STATE_TOUCH_SCROLL表示 View 处于触摸滑动状态,手指依然在屏幕上,通过pauseOnScroll变量确定是否需要暂停图片加载。这种时候大都属于慢速滚动浏览状态,所以建议继续图片加载。
OnScrollListener.SCROLL_STATE_FLING表示 View 处于甩指滚动状态,手指已离开屏幕,通过pauseOnFling变量确定是否需要暂停图片加载。这种时候大都属于快速滚动状态,所以建议暂停图片加载以节省资源。

4.2.63 QueueProcessingType.java

任务队列的处理类型,包括FIFO先进先出、LIFO后进先出。

4.2.64 LIFOLinkedBlockingDeque.java

后进先出阻塞队列。重写LinkedBlockingDequeoffer(…)函数如下:

@Override
public boolean offer(T e) {
    return super.offerFirst(e);
}

LinkedBlockingDeque插入总在最前,而remove()本身始终删除第一个元素,所以就变为了后进先出阻塞队列。
实际一般情况只重写offer(…)函数是不够的,但因为ThreadPoolExecutor默认只用到了BlockingQueueoffer(…)函数,所以这种简单重写后做为ThreadPoolExecutor的任务队列没问题。

LIFOLinkedBlockingDeque.java包下的LinkedBlockingDeque.javaBlockingDeque.javaDeque.java都是 Java 1.6 源码中的,这里不做分析。

4.2.65 DiskCacheUtils.java

磁盘缓存工具类,可用于查找或删除某个 uri 对应的磁盘缓存。

4.2.66 MemoryCacheUtils.java

内存缓存工具类。可用于根据 uri 生成内存缓存 key,缓存 key 比较,根据 uri 得到所有相关的 key 或图片,删除某个 uri 的内存缓存。
generateKey(String imageUri, ImageSize targetSize)
根据 uri 生成内存缓存 key,key 规则为[imageUri]_[width]x[height]

4.2.67 StorageUtils.java

得到图片 SD 卡缓存目录路径。
缓存目录优先选择/Android/data/[app_package_name]/cache;若无权限或不可用,则选择 App 在文件系统的缓存目录context.getCacheDir();若无权限或不可用,则选择/data/data/[app_package_name]/cache

如果缓存目录选择了/Android/data/[app_package_name]/cache,则新建.nomedia文件表示不允许类似 Galley 这些应用显示此文件夹下图片。不过在 4.0 系统有 Bug 这种方式不生效。

4.2.68 ImageSizeUtils.java

用于计算图片尺寸、缩放比例相关的工具类。

4.2.69 IoUtils.java

IO 相关工具类,包括 stream 拷贝,关闭等。

4.2.70 L.java

Log 工具类。

5. 杂谈

聊聊 LRU

UIL 的内存缓存默认使用了 LRU 算法。 LRU: Least Recently Used 近期最少使用算法, 选用了基于链表结构的 LinkedHashMap 作为存储结构。
假设情景:内存缓存设置的阈值只够存储两个 bitmap 对象,当 put 第三个 bitmap 对象时,将近期最少使用的 bitmap 对象移除。
图 1: 初始化 LinkedHashMap, 并按使用顺序来排序, accessOrder = true;
图 2: 向缓存池中放入 bitmap1 和 bitmap2 两个对象。
图 3: 继续放入第三个 bitmap3,根据假设情景,将会超过设定缓存池阈值。
图 4: 释放对 bitmap1 对象的引用。
图 5: bitmap1 对象被 GC 回收。




本文转载自:http://blog.csdn.net/oyangyujun/article/details/47419989

共有 人打赏支持
k
粉丝 1
博文 129
码字总数 0
作品 0
朝阳
Android 使用Universal Image Loader绘制带圆角的图片(一)

Android 使用Universal Image Loader绘制带圆角的图片(一) 绘制带圆角的控件难吗?貌似不难。对于一个普通layout或者widget,要绘制圆角,只要把 background设置成下面这样的drawable就行了...

yhchinabest
2015/07/20
0
0
github上的NB Android项目

最近想捣鼓捣鼓Android,下了Oschina的android client source,看得挺舒服的,写得很清晰,受益匪浅,想再深入了解下,当然是接着看优秀开源项目咯。google到CSDN上的“直接拿来用,最火的A...

pengzai
2013/05/13
0
0
安卓图片加载框架--Universal-Image-Loader

  今天来介绍图片加载的框架Android-Universal-Image-Loader   GITHUB上的下载路径为:https://github.com/nostra13/Android-Universal-Image-Loader   也可以自行百度下载。   首先...

痞子姜
2015/09/18
0
0
最美应用-从Android研发工程师的角度之[最美时光]

最美应用-从Android研发工程师的角度之最美时光 @author ASCE1885的 Github 简书 微博 CSDN 最近发现最美应用这样一个网站,它会定期推介一些很有意思的app,作为开发者,每次看到很棒的app...

2tman
2015/08/19
0
0
Design Patterns in Android:工厂方法模式

前言 今天给大家分享的是《设计模式Android篇:工厂方法模式》。 工厂方法是创建型模式的一种,可用来在适当的场合创建对象。今天将通过Android源码和Android开发案例跟大家讲解什么是工厂方...

MichaelX
07/16
0
0

没有更多内容

加载失败,请刷新页面

加载更多

中秋快乐!!!

HiBlock
22分钟前
0
0
Node安装教程

1、安装最新版的node 2、设置相关目录(以D盘为例) 分别建立目录:D:\node,D:\node\node-globa,D:\node\node-cache 命令行输入: // 设置npm国内镜像 npm config set registry https://re...

Mohan710
50分钟前
1
0
中国发布域名系统基础软件 “红枫”

9月12日消息,域名工程中心(英文缩写 ZDNS)发布了宣称自主开发的域名系统基础软件 “红枫(Maple DNS)”。 9月12日消息,域名工程中心(英文缩写 ZDNS)发布了宣称自主开发的域名系统基础软...

问题终结者
今天
3
0
Shell编程(分发系统介绍、expect远程登录、expect远程执行命令、expect传递参数)

分发系统介绍expect 分发系统expect即分发脚本,是一种脚本语言;通过他可以实现传输,输入命令(上线代码) 应用场景:业务越来越大,网站app,后端,编程语言是php,所以就需要配置lamp或者...

蛋黄_Yolks
今天
2
0
Java Http请求工具类

public static String httpPost(String source, String params) {URL url = null;HttpURLConnection conn = null;OutputStream os = null;String ret = null;try {......

yuewawa
今天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部