Android-Universal-Image-Loader是一个开源的UI组件程序,该项目的目的是提供一个可重复使用的仪器为异步图像加载,缓存和显示。
权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

ImageLoaderConfiguration是针对图片缓存的全局配置,主要有线程类、缓存大小、磁盘大小、图片下载与解析、日志方面的配置

ImageLoader是具体下载图片,缓存图片,显示图片的具体执行类,它有两个具体的方法displayImage(...)、loadImage(...),但是其实最终他们的实现都是displayImage(...)。

DisplayImageOptions用于指导每一个Imageloader根据网络图片的状态(空白、下载错误、正在下载)显示对应的图片,是否将缓存加载到磁盘上,下载完后对图片进行怎么样的处理。

public class ImageLoadUtil {
private static ImageLoadUtil imageLoadUtil = null;
private ImageLoaderConfiguration config = null;
private DisplayImageOptions options = null;
private ImageLoadUtil(Context context){
options = new DisplayImageOptions.Builder()
//.showImageOnLoading(R.drawable.ic_launcher) //设置图片在下载期间显示的图片
//.showImageForEmptyUri(R.drawable.ic_launcher)//设置图片Uri为空或是错误的时候显示的图片
//.showImageOnFail(R.drawable.ic_launcher) //设置图片加载/解码过程中错误时候显示的图片
.cacheInMemory(true)//设置下载的图片是否缓存在内存中
.cacheOnDisc(true)//设置下载的图片是否缓存在SD卡中
.considerExifParams(true) //是否考虑JPEG图像EXIF参数(旋转,翻转)
.imageScaleType(ImageScaleType.EXACTLY_STRETCHED)//设置图片以如何的编码方式显示
.bitmapConfig(Bitmap.Config.RGB_565)//设置图片的解码类型//
//.delayBeforeLoading(int delayInMillis)//int delayInMillis为你设置的下载前的延迟时间
//设置图片加入缓存前,对bitmap进行设置
//.preProcessor(BitmapProcessor preProcessor)
.resetViewBeforeLoading(true)//设置图片在下载前是否重置,复位
.displayer(new RoundedBitmapDisplayer(20))//是否设置为圆角,弧度为多少
.displayer(new FadeInBitmapDisplayer(100))//是否图片加载好后渐入的动画时间
.build();//构建完成 config = new ImageLoaderConfiguration.Builder(
context).threadPriority(Thread.NORM_PRIORITY - 2)// 加载图片的线程数
.denyCacheImageMultipleSizesInMemory() // 解码图像的大尺寸将在内存中缓存先前解码图像的小尺寸。
.discCacheFileNameGenerator(new Md5FileNameGenerator())// 设置磁盘缓存文件名称
.tasksProcessingOrder(QueueProcessingType.LIFO)// 设置加载显示图片队列进程
.writeDebugLogs() // Remove for release app
.discCache(new UnlimitedDiscCache(new File(FileCacheUtil.getPicCacheDir()))) // 文件缓存目录
.defaultDisplayImageOptions(options)// 创建配置过得DisplayImageOption对象
.build();
/*config = new ImageLoaderConfiguration.Builder(context)
.threadPriority(Thread.NORM_PRIORITY - 2)
.denyCacheImageMultipleSizesInMemory()
.diskCacheFileNameGenerator(new Md5FileNameGenerator())
.tasksProcessingOrder(QueueProcessingType.LIFO)
.writeDebugLogs()
.build();*/
ImageLoader.getInstance().init(config);
} public static ImageLoadUtil init(Context context){
if (imageLoadUtil == null) {
imageLoadUtil = new ImageLoadUtil(context);
}
return imageLoadUtil;
}
}

首先分析:ImageLoaderConfiguration

1
因为使用时使用到ImageLoaderConfiguration的构造方法,所以先看ImageLoaderConfiguration的构造方法:

//设置内存缓存的选项,用于将图片将图片解析成最大指定宽高的大小的图片进行缓存(缓存在内存中的图片宽高)。
memoryCacheExtraOptions(int maxImageWidthForMemoryCache, int maxImageHeightForMemoryCache) //设置磁盘缓存的选项,maxImageWidthForDiskCache()和maxImageHeightForDiskCache()缓存在硬盘里面图片最大尺寸。 diskCacheExtraOptions(int maxImageWidthForDiskCache, int maxImageHeightForDiskCache, BitmapProcessor processorForDiskCache) //设置自定义加载和显示任务的线程池
taskExecutor(Executor executor) //设置自定义显示任务的线程池
taskExecutorForCachedImages(Executor executorForCachedImages) //设置图片显示任务的线程池大小
threadPoolSize(int threadPoolSize) //设置线程的优先级
threadPriority(int threadPriority) //设置拒绝缓存一张图片的多个尺寸
denyCacheImageMultipleSizesInMemory() //设置加载和显示图片任务队列的类型
tasksProcessingOrder(QueueProcessingType tasksProcessingType) //设置最大内存缓存字节数
memoryCacheSize(int memoryCacheSize) //设置最大内存缓存所占app可用内存的百分比
memoryCacheSizePercentage(int availableMemoryPercent) //设置内存缓存算法
memoryCache(MemoryCache memoryCache) //设置最大磁盘缓存字节数
diskCacheSize(int maxCacheSize) //设置在磁盘缓存文件夹下最多文件数
diskCacheFileCount(int maxFileCount) //设置磁盘缓存文件生成的命名规则
diskCacheFileNameGenerator(FileNameGenerator fileNameGenerator) //设置磁盘缓存
diskCache(DiskCache diskCache) //设置下载图片的工具
imageDownloader(ImageDownloader imageDownloader) //设置decode出bitmap的工具
imageDecoder(ImageDecoder imageDecoder) //设置默认的DisplayImageOptions
defaultDisplayImageOptions(DisplayImageOptions defaultDisplayImageOptions) //log信息
writeDebugLogs() public ImageLoaderConfiguration build() {
initEmptyFieldsWithDefaultValues();
return new ImageLoaderConfiguration(this);
} 在分析DisplayImageOptions(图片加载过程中各种情况的处理): //设置图片加载过程中显示的图片
showImageOnLoading(int imageRes) //设置空URI显示的图片
showImageForEmptyUri(int imageRes) //设置发生错误显示的图片
showImageOnFail(int imageRes) //设置图片加载前是否重置
resetViewBeforeLoading(boolean resetViewBeforeLoading) //设置是否将图片缓存在内存里
cacheInMemory(boolean cacheInMemory) //设置是否将图片缓存在磁盘上
cacheOnDisk(boolean cacheOnDisk) //设置图片缩放的类型
imageScaleType(ImageScaleType imageScaleType) //设置Bitmap.Config
bitmapConfig(Bitmap.Config bitmapConfig) //设置图片解码的选项
decodingOptions(Options decodingOptions) //设置加载任务前的延迟
delayBeforeLoading(int delayInMillis) //设置下载时额外的对象
extraForDownloader(Object extra) //设置是否考虑EXIF信息
considerExifParams(boolean considerExifParams) //设置内存缓存bitmap对象前的处理
preProcessor(BitmapProcessor preProcessor) //设置内存缓存bitmap对象后的处理
postProcessor(BitmapProcessor postProcessor) //设置图片的显示方式
displayer(BitmapDisplayer displayer) //true是直接调用LoadAndDisplayImageTask对象的run方法,false是放到线程池里面执行,默认false
syncLoading(boolean isSyncLoading) //设置显示图片和触发ImageLoadingListener事件的自定义Handler对象
handler(Handler handler)

ImageLoader使用的是单利模式:

在展示的时候调用的是:displayImage和loadImage两个方法:
分析displayImage:

public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
//检查UIL的配置是否被初始化
checkConfiguration();
if (imageAware == null) {
throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);
}
if (listener == null) {
listener = emptyListener;
}
if (options == null) {
options = configuration.defaultDisplayImageOptions;
} if (TextUtils.isEmpty(uri)) {
engine.cancelDisplayTaskFor(imageAware);
listener.onLoadingStarted(uri, imageAware.getWrappedView());
//没有图片时,显示displayImage传过来的图片不存在情况下的图片
if (options.shouldShowImageForEmptyUri()) {
imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));
} else {
imageAware.setImageDrawable(null);
}
listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);
return;
}

//计算Bitmap的大小,以便后面解析图片时用

ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());
//内存缓存的名称
String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);
engine.prepareDisplayTaskFor(imageAware, memoryCacheKey); listener.onLoadingStarted(uri, imageAware.getWrappedView());
//Bitmap是否缓存在内存?
Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
if (bmp != null && !bmp.isRecycled()) {
L.d(LOG_LOAD_IMAGE_FROM_MEMORY_CACHE, memoryCacheKey); if (options.shouldPostProcess()) {
ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
options, listener, progressListener, engine.getLockForUri(uri));
//处理并显示图片
ProcessAndDisplayImageTask displayTask = new ProcessAndDisplayImageTask(engine, bmp, imageLoadingInfo,
defineHandler(options));
if (options.isSyncLoading()) {
displayTask.run();
} else {
engine.submit(displayTask);
}
} else {
//显示图片
options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
}
} else {
//根据状态显示正在加载还是加载前的情况
if (options.shouldShowImageOnLoading()) {
imageAware.setImageDrawable(options.getImageOnLoading(configuration.resources));
} else if (options.isResetViewBeforeLoading()) {
imageAware.setImageDrawable(null);
} ImageLoadingInfo imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey,
options, listener, progressListener, engine.getLockForUri(uri));
//启动一个线程,加载并显示图片
LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(engine, imageLoadingInfo,
defineHandler(options));
if (options.isSyncLoading()) {
displayTask.run();
} else {
engine.submit(displayTask);
}
}
}

再往下分析LoadAndDisplayImageTask
根据uri看看磁盘中是不是已经缓存了这个文件,如果有了,调用decodeImage方法,将图片文件decode成bitmap对象,若文件不存在,调用tryCacheImageOnDisk()方法去下载并缓存图片到本地磁盘,再通过decodeImage方法将图片文件decode成bitmap对象

private Bitmap tryLoadBitmap() throws TaskCancelledException {
Bitmap bitmap = null;
try {
//尝试从磁盘缓存中读取Bitmap
File imageFile = configuration.diskCache.get(uri);
//如果内存中有该图片,加载
if (imageFile != null && imageFile.exists()) {
L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey);
loadedFrom = LoadedFrom.DISC_CACHE; checkTaskNotActual();
bitmap = decodeImage(Scheme.FILE.wrap(imageFile.getAbsolutePath()));
}
//没有缓存在磁盘,从网络中下载图片
if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
L.d(LOG_LOAD_IMAGE_FROM_NETWORK, memoryCacheKey);
loadedFrom = LoadedFrom.NETWORK; String imageUriForDecoding = uri;
//将网络里面的图片缓存到SD卡里面
if (options.isCacheOnDisk() && tryCacheImageOnDisk()) {
imageFile = configuration.diskCache.get(uri);
if (imageFile != null) {
imageUriForDecoding = Scheme.FILE.wrap(imageFile.getAbsolutePath());
}
} checkTaskNotActual();
bitmap = decodeImage(imageUriForDecoding); if (bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
fireFailEvent(FailType.DECODING_ERROR, null);
}
}
} catch (IllegalStateException e) {
fireFailEvent(FailType.NETWORK_DENIED, null);
} catch (TaskCancelledException e) {
throw e;
} catch (IOException e) {
L.e(e);
fireFailEvent(FailType.IO_ERROR, e);
} catch (OutOfMemoryError e) {
L.e(e);
fireFailEvent(FailType.OUT_OF_MEMORY, e);
} catch (Throwable e) {
L.e(e);
fireFailEvent(FailType.UNKNOWN, e);
}
return bitmap;
} tryCacheImageOnDisk()里面是: loaded = downloadImage(); private boolean downloadImage() throws IOException {
//获取图片输入流
InputStream is = getDownloader().getStream(uri, options.getExtraForDownloader());
if (is == null) {
L.e(ERROR_NO_IMAGE_STREAM, memoryCacheKey);
return false;
} else {
try {
//不为null,进行SD卡保存
return configuration.diskCache.save(uri, is, this);
} finally {
IoUtils.closeSilently(is);
}
}
}

configuration.diskCache.save(uri, is, this),接下来看save保存图片到SD卡的程序;它先是生成一个后缀名.tmp的临时文件,通过downloader得到的输入流imageStream拷贝到OutputStream中, finally中将临时文件tmpFile重命名回imageFile,并将tmpFile删除掉, 如果这些实现都没出什么问题,就reutrn一个true, 告诉别人,我save成功了:

public boolean save(String imageUri, InputStream imageStream, IoUtils.CopyListener listener) throws IOException {
File imageFile = getFile(imageUri);
//tmp的临时文件
File tmpFile = new File(imageFile.getAbsolutePath() + TEMP_IMAGE_POSTFIX);
boolean loaded = false;
try {
OutputStream os = new BufferedOutputStream(new FileOutputStream(tmpFile), bufferSize);
try {
loaded = IoUtils.copyStream(imageStream, os, listener, bufferSize);
} finally {
//将临时文件tmpFile重命名回imageFile,并将tmpFile删除掉
IoUtils.closeSilently(os);
}
} finally {
if (loaded && !tmpFile.renameTo(imageFile)) {
loaded = false;
}
if (!loaded) {
tmpFile.delete();
}
}
//true save成功
//false save失败
return loaded;
}

http://www.cnblogs.com/kissazi2/p/3901369.html

Universal-Image-Loader分析:的更多相关文章

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

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

  2. universal image loader自己使用的一些感受

    1.全局入口的Application定义初始化: ImageLoaderConfiguration configuration = new ImageLoaderConfiguration.Build ...

  3. 【译】UNIVERSAL IMAGE LOADER. PART 3---ImageLoader详解

    在之前的文章,我们重点讲了Android-Universal-Image-Loader的三个主要组件,现在我们终于可以开始使用它了. Android-Universal-Image-Loader有四个 ...

  4. Android中Universal Image Loader开源框架的简单使用

    UIL (Universal Image Loader)aims to provide a powerful, flexible and highly customizable instrument ...

  5. universal image loader在listview/gridview中滚动时重复加载图片的问题及解决方法

    在listview/gridview中使用UIL来display每个item的图片,当图片数量较多需要滑动滚动时会出现卡顿,而且加载过的图片再次上翻后依然会重复加载(显示设置好的加载中图片) 最近在使 ...

  6. 【Android应用开发】 Universal Image Loader ( 使用简介 | 示例代码解析 )

    作者 : 韩曙亮 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/50824912 相关地址介绍 : -- Universal I ...

  7. 开源项目Universal Image Loader for Android 说明文档 (1) 简介

     When developing applications for Android, one often facesthe problem of displaying some graphical ...

  8. 开源项目Universal Image Loader for Android 说明文档 (1) 简单介绍

     When developing applications for Android, one often facesthe problem of displaying some graphical ...

  9. 9 loader - 分析webpack调用第三方loader的过程

    注意:webpack处理第三方文件类型的过程: 1.发现这个要处理的文件不是JS文件,然后就去配置文件中,查找有没有对应的第三方loader规则 2.如果能找到对应的规则,就会调用对应的loader处 ...

  10. 【译】UNIVERSAL IMAGE LOADER.PART 2---ImageLoaderConfiguration详解

    ImageLoader类中包含了所有操作.他是一个单例,为了获取它的一个单一实例,你需要调用getInstance()方法.在使用ImageLoader来显示图片之前,你需要初始化它的配置-Image ...

随机推荐

  1. Openjudge-计算概论(A)-奇数求和

    描述: 计算非负整数 m 到 n(包括m 和 n )之间的所有奇数的和,其中,m 不大于 n,且n 不大于300.例如 m=3, n=12, 其和则为:3+5+7+9+11=35. 输入两个数 m 和 ...

  2. 3.编写BinIoDemo.java的Java应用程序,程序完成的功能是:完成1.doc文件的复制,复制以后的文件的名称为自己的学号姓名.doc。

    package zuoye; import java.io.FileInputStream; import java.io.FileOutputStream; public class BinIoDe ...

  3. struts2 result type的类型

    一共十种类型 1.dispatcher 默认的类型,相当于servlet的foward,服务器端跳转.客户端看到的是struts2中配置的地址,而不是真正页面的地址.一般用于跳转到jsp页面 2.re ...

  4. Struts2--课程笔记3

    获取ServletAPI: 第一种方式: //在request域中放入属性req,暂且认为getContext()获取的是request域空间,但实际不是        ActionContext.g ...

  5. LYF模板连接.txt

    在解决方案里创建了一个新建网站,在其右键下添加一个模板后,准备使用模板的,在添加新建项里突然没有“使用模板页的web窗体”,顿时感觉悲剧... 解决方法:模板页代码---LYFMaterPage.Ma ...

  6. Ubuntu编译安装PHP7

    参数配置 ./configure --prefix=/usr/local/php7 \ --with-config-file-path=/usr/local/php7/etc \ --with-apx ...

  7. HDU 5806 NanoApe Loves Sequence Ⅱ

    将大于等于m的数改为1,其余的改为0.问题转变成了有多少个区间的区间和>=k.可以枚举起点,二分第一个终点 或者尺取法. #pragma comment(linker, "/STACK ...

  8. C# var 隐式类型 var 用法 特点

    var 关键字是C# 3.0 开始,在方法范围中声明的变量: var有以下特点: * 1.var在编译器编译的时候根据初始值推断出其的类型          * 2.不能赋值除了初始值类型之外的其他类 ...

  9. shell变量的替换

    1 shell变量基础shell变量是一种很“弱”的变量,默认情况下,一个变量保存一个串,shell不关心这个串是什么含义.所以若要进行数学运算,必须使用一些命令例如let.declare.expr. ...

  10. Eclipse的WorkingSet使用(转载)

    Eclipse作为一款流行的JavaIDE开发工具,其有很多好用的功能为我们的开发提供帮助.但我们的工作空间中有很多项目时,管理起来就很头疼了. 但是我们又不想更换工作区间,所以我们需要一个更加有效的 ...