zoukankan      html  css  js  c++  java
  • Universal-Image-Loader分析:

    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

  • 相关阅读:
    (转)怎样获得与激活Windows 7超级管理员权限
    (转) C代码优化方案
    英语词汇立体记忆 02
    (转)LUA和C之间的函数调用
    通过lua自带例子学习lua 01
    英语词汇立体记忆 01
    反射(类加载内存分析)
    反射(类加载器的作用)
    反射(动态创建对象操作属性)
    反射(分析类初始化)
  • 原文地址:https://www.cnblogs.com/androidsuperman/p/4240436.html
Copyright © 2011-2022 走看看