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. MySQL DATE_FORMAT

    MySQL   DATE_FORMAT(date,format) 根据format字符串格式化date值 (在format字符串中可用标志符: %M 月名字(January……December) %W ...

  2. Yii2.0 多条件搜索 带分页

                                   方法一   在控制器中 ; if($titles!=""){ $where.=" and title lik ...

  3. 《JavaScript高级程序设计》读书笔记 ---基本概念小结

     ECMAScript 中的基本数据类型包括Undefined.Null.Boolean.Number 和String. 与其他语言不同,ECMScript 没有为整数和浮点数值分别定义不同的数据 ...

  4. Xcode8.2 继续使用插件

    网上参考了文章:http://www.jianshu.com/p/ab819babf2c3 使用的是:update_xcode_plugins . 但要注意的是,在Xcode 8.2下安装,并没有给我 ...

  5. 《Windows驱动开发技术详解》之驱动程序的同步处理

    中断请求级 中断请求被分为软件中断和硬件中断两种,这些中断都映射成不同级别的中断请求级.每个中断请求都有各自的优先级别,正在运行的线程随时都可以被中断打断,进入到中断处理程序.优先级高的中断来临时,处 ...

  6. 你所不知道的mybatis居然也有拦截器

    对于mybatis的拦截器这个想法我来自于三个地方 也就是下面这个三个地方是可以使用的,其他的情况需要开发人员根据实际情况来使用. 1.对于分页的查询,我们可以对于分页的方法采用比较规范的命名,然后根 ...

  7. Oracle小技术集锦

  8. 安装阿里云的php+mysql+nginx+vsftpd

    百度云search   sh-1.3.0-centos.zip

  9. htaccess 实现网址缩短

    访问 :app.xxx.com/a 解析到:app.xxx.com/index.php/app/a <IfModule mod_rewrite.c> RewriteEngine on Re ...

  10. linux下mysql root密码忘记修改方法

    一.MySQL密码的恢复方法之一 如果忘记了MySQL的root密码,可以用以下方法重新设置:1.切换到root下su root 2. KILL掉系统里的MySQL进程: killall -TERM ...