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. tomcat的事件监听

    //事件涉及的三个组件:事件源.事件对象.事件监听器 //一个总的事件监听器接口,所有不同分类的事件监听器都继承这个接口 public interface EventListener {} //例如  ...

  2. 如何为CentOS 7配置静态IP地址

    问题:在CentOS 7上,我想要将我其中一个网络接口从DHCP改为静态IP地址配置,如何才能永久为CentOS或RHEL 7上的网络接口分配静态IP地址? 如果你想要为CentOS 7中的某个网络接 ...

  3. Alyona and a tree

    Alyona and a tree time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...

  4. mac mysql下载

    mysql下载地址:http://dev.mysql.com/downloads/mysql/,不需要账号的 mysql创建数据库,默认字符集是latin1,可以指定字符集. mac删除mysql c ...

  5. NOIP2014提高组第二题联合权值

    还是先看题吧: 试题描述  无向连通图 G 有 n 个点,n-1 条边.点从 1 到 n 依次编号,编号为 i 的点的权值为 Wi ,每条边的长度均为 1.图上两点(u, v)的距离定义为 u 点到 ...

  6. VBS脚本操作网页元素

    =================打开百度,点击百度按钮==================== Dim btn,ieSet ie = WScript.CreateObject("Inter ...

  7. TD8.0迁移到QC9.2,自动迁移失败,手动迁移

    源机器A:TD8.0+SQLServer2000目标机器B:QC9.2+SQLServer2000 一:自动迁移,1.在A在A上安装QC迁移工具,然后在B中点击TOOLS>>Migrati ...

  8. Javascript:scrollWidth,clientWidth,offsetWidth的区别(转)

    网页可见区域宽:document.body.clientWidth; 网页可见区域高:document.body.clientHeight; 网页可见区域高:document.body.offsetW ...

  9. MVC 数据绑定

    在做Asp.Net MVC项目中,都知道View负责页面展示数据或者提供页面收集数据,而所展示的数据或者收集的数据都是从Controller的Action中获取或提交到Controller的Actio ...

  10. HDU2535:Vote

    Problem Description 美国大选是按各州的投票结果来确定最终的结果的,如果得到超过一半的州的支持就可以当选,而每个州的投票结果又是由该州选民投票产生的,如果某个州超过一半的选民支持希拉 ...