史上最全Universal-Image-Loader源码解析————核心代码篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a820703048/article/details/79201111

背景

接着上一篇的内容,我们接着看ImageLoader的核心代码篇,上一篇主要是看ImageLoader的内存优化,主要包括磁盘缓存和内存缓存,还有就是内存的缓存策略,这一篇,我们重点来看一下ImageLoader是如何使用这些内存和进行图片的展示和图片处理和下载的。

一、code组织框架

首先我们先看code包下面的组织框架,然后我们再每个类去分析,最后我们全部串起来学习。核心代码篇和上一篇缓存篇不一样,核心代码量较多,但是我们博客篇幅有限,我们只能按重要程度,将大部分进行讲解,不多说先上截图。

这里写图片描述

二 、详细代码及类讲解

(1)ImageLoader

这个类可能是开发者最先接触或者说印象最深刻的类了,我们来看一下我们是怎么接触它的,我们来看一下它的最简单使用和源码的实现。

   //创建默认的ImageLoader配置参数
         ImageLoaderConfiguration configuration = ImageLoaderConfiguration
                .createDefault(this);
     ImageLoader.getInstance().init(configuration);
      ImageLoader.getInstance().displayImage(imageUrl, mImageView, options);
/**
 * ImageLoader是核心主类之一
 */
public class ImageLoader {
    public static final String TAG = ImageLoader.class.getSimpleName();
    static final String LOG_INIT_CONFIG = "Initialize ImageLoader with configuration";
    static final String LOG_DESTROY = "Destroy ImageLoader";
    static final String LOG_LOAD_IMAGE_FROM_MEMORY_CACHE = "Load image from memory cache [%s]";
    private static final String WARNING_RE_INIT_CONFIG = "Try to initialize ImageLoader which had already been initialized before. " + "To re-init ImageLoader with new configuration call ImageLoader.destroy() at first.";
    private static final String ERROR_WRONG_ARGUMENTS = "Wrong arguments were passed to displayImage() method (ImageView reference must not be null)";
    private static final String ERROR_NOT_INIT = "ImageLoader must be init with configuration before using";
    private static final String ERROR_INIT_CONFIG_WITH_NULL = "ImageLoader configuration can not be initialized with null";
    private ImageLoaderConfiguration configuration;//参数
    private ImageLoaderEngine engine;//核心
    //默认是使用简单的监听器
    private ImageLoadingListener defaultListener = new SimpleImageLoadingListener();
    private volatile static ImageLoader instance;
    /**
     * 先来个单例模式
     */
    public static ImageLoader getInstance() {
        if (instance == null) {
            synchronized (ImageLoader.class) {
                if (instance == null) {
                    instance = new ImageLoader();
                }
            }
        }
        return instance;
    }
    protected ImageLoader() {
    }
    /**
     * 使用者先配置参数然后初始化进来
     */
    public synchronized void init(ImageLoaderConfiguration configuration) {
        if (configuration == null) {
            throw new IllegalArgumentException(ERROR_INIT_CONFIG_WITH_NULL);
        }
        if (this.configuration == null) {
            engine = new ImageLoaderEngine(configuration);
            this.configuration = configuration;
        } else {
        }
    }
    /**
     * 判断是否被初始化
     */
    public boolean isInited() {
        return configuration != null;
    }
    /**
     * 多级调用 将imageview转化为imageAware
     */
    public void displayImage(String uri, ImageAware imageAware) {
        displayImage(uri, imageAware, null, null, null);
    }
    /**
     * 多级调用加监听
     */
    public void displayImage(String uri, ImageAware imageAware, ImageLoadingListener listener) {
        displayImage(uri, imageAware, null, listener, null);
    }
    /**
     * 调用加展示参数
     */
    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options) {
        displayImage(uri, imageAware, options, null, null);
    }
    /**
     * 进行多级调用 两者都有
     */
    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
                             ImageLoadingListener listener) {
        displayImage(uri, imageAware, options, listener, null);
    }
    /**
     * 这个参数有加了参数和监听器和进度条监听器
     */
    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
                             ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        displayImage(uri, imageAware, options, null, listener, progressListener);
    }
    /**
     * 所有方法最终走到这里
     */
    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options,
                             ImageSize targetSize, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        checkConfiguration();//检查 是否有配置文件
        if (imageAware == null) {//都是判断了
            throw new IllegalArgumentException(ERROR_WRONG_ARGUMENTS);
        }
        if (listener == null) {
            listener = defaultListener;
        }
        if (options == null) {
            options = configuration.defaultDisplayImageOptions;
        }
        if (TextUtils.isEmpty(uri)) {//第一行 判断uri是否是空 如果是空 直接取消engine中的任务
            engine.cancelDisplayTaskFor(imageAware);
            listener.onLoadingStarted(uri, imageAware.getWrappedView());//然后调用listener的start
            if (options.shouldShowImageForEmptyUri()) {//由于 uri为空 如果设置了需要设置空的图像那么直接设置 图像是 空的时候需要设置的图像即可 如果没设置,直接不显示就好
                imageAware.setImageDrawable(options.getImageForEmptyUri(configuration.resources));
            } else {
                imageAware.setImageDrawable(null);
            }//之后调用 complete 回调 返回 这是uri为空的情况 不需要做太多操作 也不需要缓存
            listener.onLoadingComplete(uri, imageAware.getWrappedView(), null);
            return;
        }
        if (targetSize == null) {//像的大小 设置是空 那么根据控件设置的大小 设置 要展示图片的大小
            targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, configuration.getMaxImageSize());
        }
//之后 根据 uri和目标的大小 生成一个key 并把 这个任务放入 engine 的集合中
        //   回调 started方法
        String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);
        engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);

        listener.onLoadingStarted(uri, imageAware.getWrappedView());
       // 从内存缓存中根据key取bitmap
        Bitmap bmp = configuration.memoryCache.get(memoryCacheKey);
        //如果存在 并且没被回收
        if (bmp != null && !bmp.isRecycled()) {
//如果设置了 postProcess 执行 默认没设置 设置这个可以提前对图片进行某些处理
            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 {
                //不需要 在展示图片之前处理图片时,那么就直接使用 displaywe 对 图片进行 展示 并回调complete函数
                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 和 任务LoadAndDisplayImageTask
            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);
            }
        }
    }
    /**
     * 用户直接在外面调用的,里面将他转成了ImageViewAware
     */
    public void displayImage(String uri, ImageView imageView) {
        displayImage(uri, new ImageViewAware(imageView), null, null, null);
    }

    /**
     * 展示图片添加图片大小
     */
    public void displayImage(String uri, ImageView imageView, ImageSize targetImageSize) {
        displayImage(uri, new ImageViewAware(imageView), null, targetImageSize, null, null);
    }
    /**
     * 展示图片加参数
     */
    public void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {
        displayImage(uri, new ImageViewAware(imageView), options, null, null);
    }
    /**
     * 图片加监听
     */
    public void displayImage(String uri, ImageView imageView, ImageLoadingListener listener) {
        displayImage(uri, new ImageViewAware(imageView), null, listener, null);
    }
    public void displayImage(String uri, ImageView imageView, DisplayImageOptions options,
                             ImageLoadingListener listener) {
        displayImage(uri, imageView, options, listener, null);
    }
    /**
     * 展示图片加监听加进度条
     */
    public void displayImage(String uri, ImageView imageView, DisplayImageOptions options,
                             ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        displayImage(uri, new ImageViewAware(imageView), options, listener, progressListener);
    }
    /**
     * 展示图片加监听
     */
    public void loadImage(String uri, ImageLoadingListener listener) {
        loadImage(uri, null, null, listener, null);
    }
    /**
     * 展示图片加内存限制加监听
     */
    public void loadImage(String uri, ImageSize targetImageSize, ImageLoadingListener listener) {
        loadImage(uri, targetImageSize, null, listener, null);
    }
    /**
     */
    public void loadImage(String uri, DisplayImageOptions options, ImageLoadingListener listener) {
        loadImage(uri, null, options, listener, null);
    }
    /**
     * 展示图片加目标大小
     */
    public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options,
                          ImageLoadingListener listener) {
        loadImage(uri, targetImageSize, options, listener, null);
    }
    /**
     * 展示图片 所有参数都加
     */
    public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options,
                          ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        checkConfiguration();
        if (targetImageSize == null) {
            targetImageSize = configuration.getMaxImageSize();
        }
        if (options == null) {
            options = configuration.defaultDisplayImageOptions;
        }
        NonViewAware imageAware = new NonViewAware(uri, targetImageSize, ViewScaleType.CROP);
        displayImage(uri, imageAware, options, listener, progressListener);
    }
    /**
     * 加载图片 异步的
     */
    public Bitmap loadImageSync(String uri) {
        return loadImageSync(uri, null, null);
    }
    /**
     * 加载图片异步加参数
     */
    public Bitmap loadImageSync(String uri, DisplayImageOptions options) {
        return loadImageSync(uri, null, options);
    }
    /**
     * 加载图片限制图片大小
     */
    public Bitmap loadImageSync(String uri, ImageSize targetImageSize) {
        return loadImageSync(uri, targetImageSize, null);
    }
    /**
     * 加载图片异步
     */
    public Bitmap loadImageSync(String uri, ImageSize targetImageSize, DisplayImageOptions options) {
        if (options == null) {
            options = configuration.defaultDisplayImageOptions;
        }
        options = new DisplayImageOptions.Builder().cloneFrom(options).syncLoading(true).build();
        SyncImageLoadingListener listener = new SyncImageLoadingListener();
        loadImage(uri, targetImageSize, options, listener);
        return listener.getLoadedBitmap();
    }

    /**
     * Checks if ImageLoader's configuration was initialized
     * 检查配置
     */
    private void checkConfiguration() {
        if (configuration == null) {
            throw new IllegalStateException(ERROR_NOT_INIT);
        }
    }

    /**
     * 设置监听器.
     */
    public void setDefaultLoadingListener(ImageLoadingListener listener) {
        defaultListener = listener == null ? new SimpleImageLoadingListener() : listener;
    }
    /**
     * Returns memory cache
     * 返回内存策略
     *
     * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
     */
    public MemoryCache getMemoryCache() {
        checkConfiguration();
        return configuration.memoryCache;
    }
    /**
     * Clears memory cache
     *
     * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
     */
    public void clearMemoryCache() {
        checkConfiguration();
        configuration.memoryCache.clear();
    }
    /**
     * Returns disk cache
     * 返回磁盘缓存
     *
     * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
     * @deprecated Use {@link #getDiskCache()} instead
     */
    @Deprecated
    public DiskCache getDiscCache() {
        return getDiskCache();
    }

    /**
     * Returns disk cache
     *
     * @throws IllegalStateException if {@link #init(ImageLoaderConfiguration)} method wasn't called before
     */
    public DiskCache getDiskCache() {
        checkConfiguration();
        return configuration.diskCache;
    }
    /**
     * Clears disk cache.
     */
    @Deprecated
    public void clearDiscCache() {
        clearDiskCache();
    }

    /**
     * Clears disk cache.
     */
    public void clearDiskCache() {
        checkConfiguration();
        configuration.diskCache.clear();
    }

    /**
     * Returns URI of image which is loading at this moment into passed
     */
    public String getLoadingUriForView(ImageAware imageAware) {
        return engine.getLoadingUriForView(imageAware);
    }

    /**
     * Returns URI of image which is loading at this moment into passed
     */
    public String getLoadingUriForView(ImageView imageView) {
        return engine.getLoadingUriForView(new ImageViewAware(imageView));
    }

    /**
     * Cancel the task of loading and displaying image for passed
     * which display task will be cancelled
     */
    public void cancelDisplayTask(ImageAware imageAware) {
        engine.cancelDisplayTaskFor(imageAware);
    }

    /**
     */
    public void cancelDisplayTask(ImageView imageView) {
        engine.cancelDisplayTaskFor(new ImageViewAware(imageView));
    }

    /**
     * 拒绝网络下载
     */
    public void denyNetworkDownloads(boolean denyNetworkDownloads) {
        engine.denyNetworkDownloads(denyNetworkDownloads);
    }

    /**
     * 处理网络慢
     * - otherwise.
     */
    public void handleSlowNetwork(boolean handleSlowNetwork) {
        engine.handleSlowNetwork(handleSlowNetwork);
    }

    /**
     */
    public void pause() {
        engine.pause();
    }

    /**
     *
     */
    public void resume() {
        engine.resume();
    }

    /**
     */
    public void stop() {
        engine.stop();
    }

    /**
     * 销毁
     */
    public void destroy() {
        stop();
        configuration.diskCache.close();
        engine = null;
        configuration = null;
    }
    private static Handler defineHandler(DisplayImageOptions options) {
        Handler handler = options.getHandler();
        if (options.isSyncLoading()) {
            handler = null;
        } else if (handler == null && Looper.myLooper() == Looper.getMainLooper()) {
            handler = new Handler();
        }
        return handler;
    }
    /**
     * Listener which is designed for synchronous image loading.
     */
    private static class SyncImageLoadingListener extends SimpleImageLoadingListener {
        private Bitmap loadedImage;
        @Override
        public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
            this.loadedImage = loadedImage;
        }
        public Bitmap getLoadedBitmap() {
            return loadedImage;
        }
    }
}

(2)DefaultConfigurationFactory

这个类是一个使用工厂模式方法提供一个队imageloader的参数配置,通过这个类,可以创建一系列的配置参数,通过代码我们可以清楚的看到,它默认使用hashcode的磁盘命名,如果磁盘没有传大小,那么就会使用无限的磁盘缓存策略,如果有传大小的话,那么就使用最近最少使用的磁盘缓存策略,内存缓存的话,如果有传大小,那么使用这个传的大小,如果没有穿参数的话,那么就使用app最大的八分之一,使用最近最少缓存策略,还有就是创建一些图片展示器之类的。

/**
 * Factory for providing of default options for {@linkplain ImageLoaderConfiguration configuration}
 *一个工厂提供默认的操作对imageloader的参数
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
 * @since 1.5.6
 */
public class DefaultConfigurationFactory {
    /** 创建一个默认的执行器 */
    public static Executor createExecutor(int threadPoolSize, int threadPriority,
            QueueProcessingType tasksProcessingType) {
        boolean lifo = tasksProcessingType == QueueProcessingType.LIFO;
        BlockingQueue<Runnable> taskQueue =
                lifo ? new LIFOLinkedBlockingDeque<Runnable>() : new LinkedBlockingQueue<Runnable>();
        return new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 0L, TimeUnit.MILLISECONDS, taskQueue,
                createThreadFactory(threadPriority, "uil-pool-"));
    }

    /** /默认的任务分发Executor  */
    public static Executor createTaskDistributor() {
        return Executors.newCachedThreadPool(createThreadFactory(Thread.NORM_PRIORITY, "uil-pool-d-"));
    }

    /**默认的磁盘缓存文件名的生成策略   */
    public static FileNameGenerator createFileNameGenerator() {
        return new HashCodeFileNameGenerator();
    }

    /**
     * 默认的硬件缓存配置  如果值为0的话就用无限的磁盘缓存 如果大于0就用最近最少使用缓存
     */
    public static DiskCache createDiskCache(Context context, FileNameGenerator diskCacheFileNameGenerator,
                                            long diskCacheSize, int diskCacheFileCount) {
        File reserveCacheDir = createReserveDiskCacheDir(context);
        if (diskCacheSize > 0 || diskCacheFileCount > 0) {
            File individualCacheDir = StorageUtils.getIndividualCacheDirectory(context);
            try {
                return new LruDiskCache(individualCacheDir, reserveCacheDir, diskCacheFileNameGenerator, diskCacheSize,
                        diskCacheFileCount);
            } catch (IOException e) {
                L.e(e);
                // continue and create unlimited cache
            }
        }
        File cacheDir = StorageUtils.getCacheDirectory(context);
        return new UnlimitedDiskCache(cacheDir, reserveCacheDir, diskCacheFileNameGenerator);
    }

    /** Creates reserve disk cache folder which will be used if primary disk cache folder becomes unavailable */
    private static File createReserveDiskCacheDir(Context context) {//默认的备用硬件缓存目录
        File cacheDir = StorageUtils.getCacheDirectory(context, false);
        File individualDir = new File(cacheDir, "uil-images");
        if (individualDir.exists() || individualDir.mkdir()) {
            cacheDir = individualDir;
        }
        return cacheDir;
    }

    /**
     * Creates default implementation of {@link MemoryCache} - {@link LruMemoryCache}<br />
     * Default cache size = 1/8 of available app memory.
     *
     * 配置 如果传入的默认大小为0 那么就拿到App最大内存的八分之一
     * 如果不为0 那么就用传入的大小来作为最近最少使用算法的内存
     */
    public static MemoryCache createMemoryCache(Context context, int memoryCacheSize) {
        if (memoryCacheSize == 0) {
            ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
            int memoryClass = am.getMemoryClass();
            if (hasHoneycomb() && isLargeHeap(context)) {
                memoryClass = getLargeMemoryClass(am);
            }
            memoryCacheSize = 1024 * 1024 * memoryClass / 8;
        }
        return new LruMemoryCache(memoryCacheSize);
    }

    private static boolean hasHoneycomb() {
        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private static boolean isLargeHeap(Context context) {
        return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0;
    }
      //
    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private static int getLargeMemoryClass(ActivityManager am) {
        return am.getLargeMemoryClass();
    }
     //创建一个图片下载器
    /** Creates default implementation of {@link ImageDownloader} - {@link BaseImageDownloader} */
    public static ImageDownloader createImageDownloader(Context context) {
        return new BaseImageDownloader(context);
    }
       //创建一个图片修改器
    /** Creates default implementation of {@link ImageDecoder} - {@link BaseImageDecoder} */
    public static ImageDecoder createImageDecoder(boolean loggingEnabled) {
        return new BaseImageDecoder(loggingEnabled);
    }
//默认的BitmapDisplayer
    /** Creates default implementation of {@link BitmapDisplayer} - {@link SimpleBitmapDisplayer} */
    public static BitmapDisplayer createBitmapDisplayer() {
        return new SimpleBitmapDisplayer();
    }
//默认的TreadFactory
    /** Creates default implementation of {@linkplain ThreadFactory thread factory} for task executor */
    private static ThreadFactory createThreadFactory(int threadPriority, String threadNamePrefix) {
        return new DefaultThreadFactory(threadPriority, threadNamePrefix);
    }

    private static class DefaultThreadFactory implements ThreadFactory {

        private static final AtomicInteger poolNumber = new AtomicInteger(1);

        private final ThreadGroup group;
        private final AtomicInteger threadNumber = new AtomicInteger(1);
        private final String namePrefix;
        private final int threadPriority;

        DefaultThreadFactory(int threadPriority, String threadNamePrefix) {
            this.threadPriority = threadPriority;
            group = Thread.currentThread().getThreadGroup();
            namePrefix = threadNamePrefix + poolNumber.getAndIncrement() + "-thread-";
        }

        @Override
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
            if (t.isDaemon()) t.setDaemon(false);
            t.setPriority(threadPriority);
            return t;
        }
    }
}

(3)DisplayBitmapTask

一个显示图片任务的类,开了一个子线程实现Runnable接口,主要是run的一个判断,注解才是重点

/**
 *显示图片任务的一个类
 */
final class DisplayBitmapTask implements Runnable {

    private static final String LOG_DISPLAY_IMAGE_IN_IMAGEAWARE = "Display image in ImageAware (loaded from %1$s) [%2$s]";
    private static final String LOG_TASK_CANCELLED_IMAGEAWARE_REUSED = "ImageAware is reused for another image. Task is cancelled. [%s]";
    private static final String LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED = "ImageAware was collected by GC. Task is cancelled. [%s]";

    private final Bitmap bitmap;
    private final String imageUri;//
    private final ImageAware imageAware;//
    private final String memoryCacheKey;
    private final BitmapDisplayer displayer;
    private final ImageLoadingListener listener;
    private final ImageLoaderEngine engine;
    private final LoadedFrom loadedFrom;
   //初始化
    public DisplayBitmapTask(Bitmap bitmap, ImageLoadingInfo imageLoadingInfo, ImageLoaderEngine engine,
            LoadedFrom loadedFrom) {
        this.bitmap = bitmap;
        imageUri = imageLoadingInfo.uri;
        imageAware = imageLoadingInfo.imageAware;
        memoryCacheKey = imageLoadingInfo.memoryCacheKey;
        displayer = imageLoadingInfo.options.getDisplayer();
        listener = imageLoadingInfo.listener;
        this.engine = engine;
        this.loadedFrom = loadedFrom;
    }

    @Override
    public void run() {
        if (imageAware.isCollected()) {//判断图片View是否已经被回收了,如果已经被回收,则取消任务
            L.d(LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED, memoryCacheKey);
            listener.onLoadingCancelled(imageUri, imageAware.getWrappedView());
        } else if (isViewWasReused()) {//图片View是否又用来展示其他图片了,如果是的话,则取消任务
            L.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey);
            listener.onLoadingCancelled(imageUri, imageAware.getWrappedView());
        } else {//展示图片 完成接口回调
            L.d(LOG_DISPLAY_IMAGE_IN_IMAGEAWARE, loadedFrom, memoryCacheKey);
            displayer.display(bitmap, imageAware, loadedFrom);
            engine.cancelDisplayTaskFor(imageAware);
            listener.onLoadingComplete(imageUri, imageAware.getWrappedView(), bitmap);
        }
    }

    /** 检查imageview是否有效 */
    private boolean isViewWasReused() {
        String currentCacheKey = engine.getLoadingUriForView(imageAware);
        return !memoryCacheKey.equals(currentCacheKey);
    }
}

(4)DisplayImageOptions

展示图片的一个参数操作,展示的时候传入参数,展示的图片会根据传入的参数进行展示。

/**
 * 展示图片的一个参数操作
 */
public final class DisplayImageOptions {
    private final int imageResOnLoading;
    private final int imageResForEmptyUri;
    private final int imageResOnFail;
    private final Drawable imageOnLoading;
    private final Drawable imageForEmptyUri;
    private final Drawable imageOnFail;
    private final boolean resetViewBeforeLoading;
    private final boolean cacheInMemory;
    private final boolean cacheOnDisk;
    private final ImageScaleType imageScaleType;
    private final Options decodingOptions;
    private final int delayBeforeLoading;
    private final boolean considerExifParams;
    private final Object extraForDownloader;
    private final BitmapProcessor preProcessor;
    private final BitmapProcessor postProcessor;
    private final BitmapDisplayer displayer;
    private final Handler handler;
    private final boolean isSyncLoading;

    private DisplayImageOptions(Builder builder) {
        imageResOnLoading = builder.imageResOnLoading;
        imageResForEmptyUri = builder.imageResForEmptyUri;
        imageResOnFail = builder.imageResOnFail;
        imageOnLoading = builder.imageOnLoading;
        imageForEmptyUri = builder.imageForEmptyUri;
        imageOnFail = builder.imageOnFail;
        resetViewBeforeLoading = builder.resetViewBeforeLoading;
        cacheInMemory = builder.cacheInMemory;
        cacheOnDisk = builder.cacheOnDisk;
        imageScaleType = builder.imageScaleType;
        decodingOptions = builder.decodingOptions;
        delayBeforeLoading = builder.delayBeforeLoading;
        considerExifParams = builder.considerExifParams;
        extraForDownloader = builder.extraForDownloader;
        preProcessor = builder.preProcessor;
        postProcessor = builder.postProcessor;
        displayer = builder.displayer;
        handler = builder.handler;
        isSyncLoading = builder.isSyncLoading;
    }
   //判断是否在下载的时候需要显示图片
    public boolean shouldShowImageOnLoading() {
        return imageOnLoading != null || imageResOnLoading != 0;
    }
 //空uri的时候是否需要显示图片
    public boolean shouldShowImageForEmptyUri() {
        return imageForEmptyUri != null || imageResForEmptyUri != 0;
    }
 //是否需要显示图片在下载失败的时候
    public boolean shouldShowImageOnFail() {
        return imageOnFail != null || imageResOnFail != 0;
    }
//是否应该提前处理图片
    public boolean shouldPreProcess() {
        return preProcessor != null;
    }
//是否后面需要处理图片
    public boolean shouldPostProcess() {
        return postProcessor != null;
    }
//是否延迟加载图片
    public boolean shouldDelayBeforeLoading() {
        return delayBeforeLoading > 0;
    }
//拿到图片
    public Drawable getImageOnLoading(Resources res) {
        return imageResOnLoading != 0 ? res.getDrawable(imageResOnLoading) : imageOnLoading;
    }
    //拿到图片
    public Drawable getImageForEmptyUri(Resources res) {
        return imageResForEmptyUri != 0 ? res.getDrawable(imageResForEmptyUri) : imageForEmptyUri;
    }
    //拿到图片
    public Drawable getImageOnFail(Resources res) {
        return imageResOnFail != 0 ? res.getDrawable(imageResOnFail) : imageOnFail;
    }
    //是否重置view
    public boolean isResetViewBeforeLoading() {
        return resetViewBeforeLoading;
    }
    //要不要存到内存中
    public boolean isCacheInMemory() {
        return cacheInMemory;
    }
//要不要存到磁盘中
    public boolean isCacheOnDisk() {
        return cacheOnDisk;
    }
//缩放类型
    public ImageScaleType getImageScaleType() {
        return imageScaleType;
    }
    //操作类型
    public Options getDecodingOptions() {
        return decodingOptions;
    }
     //延迟加载
    public int getDelayBeforeLoading() {
        return delayBeforeLoading;
    }

    public boolean isConsiderExifParams() {
        return considerExifParams;
    }
 //拿到额外添加参数
    public Object getExtraForDownloader() {
        return extraForDownloader;
    }
 //拿到提前处理
    public BitmapProcessor getPreProcessor() {
        return preProcessor;
    }
//拿到处理后
    public BitmapProcessor getPostProcessor() {
        return postProcessor;
    }
//拿到展示器
    public BitmapDisplayer getDisplayer() {
        return displayer;
    }

    public Handler getHandler() {
        return handler;
    }
    boolean isSyncLoading() {
        return isSyncLoading;
    }
    /**
     * Builder for {@link DisplayImageOptions}
     */
    public static class Builder {
        private int imageResOnLoading = 0; //在图片下载期间显示的图片
        private int imageResForEmptyUri = 0;//设置图片Uri为空或是错误的时候显示的图片
        private int imageResOnFail = 0;  //设置图片加载/解码过程中错误时候显示的图片
        private Drawable imageOnLoading = null;//在图片下载期间显示的图片
        private Drawable imageForEmptyUri = null;//设置图片Uri为空或是错误的时候显示的图片
        private Drawable imageOnFail = null;//设置图片加载/解码过程中错误时候显示的图片
        private boolean resetViewBeforeLoading = false; //设置图片在下载前是否重置,复位
        private boolean cacheInMemory = false;//设置下载的图片是否缓存在内存中
        private boolean cacheOnDisk = false;  //设置下载的图片是否缓存在SD卡中
        private ImageScaleType imageScaleType = ImageScaleType.IN_SAMPLE_POWER_OF_2;
        private Options decodingOptions = new Options(); //设置图片的解码类型   //设置图片的解码配置
        private int delayBeforeLoading = 0;//设置图片下载前的延迟
        private boolean considerExifParams = false;//设置图片以如何的编码方式显示
        private Object extraForDownloader = null;//设置额外的内容给ImageDownloade
        private BitmapProcessor preProcessor = null;//设置图片加入缓存前,对bitmap进行设置
        private BitmapProcessor postProcessor = null; //设置显示前的图片,显示后这个图片一直保留在缓存中
        private BitmapDisplayer displayer = DefaultConfigurationFactory.createBitmapDisplayer();
        private Handler handler = null;
        private boolean isSyncLoading = false;
        /**
         * 设置参数字段参考上面注释
         */
        @Deprecated
        public Builder showStubImage(int imageRes) {
            imageResOnLoading = imageRes;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder showImageOnLoading(int imageRes) {
            imageResOnLoading = imageRes;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder showImageOnLoading(Drawable drawable) {
            imageOnLoading = drawable;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder showImageForEmptyUri(int imageRes) {
            imageResForEmptyUri = imageRes;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder showImageForEmptyUri(Drawable drawable) {
            imageForEmptyUri = drawable;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder showImageOnFail(int imageRes) {
            imageResOnFail = imageRes;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder showImageOnFail(Drawable drawable) {
            imageOnFail = drawable;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder resetViewBeforeLoading() {
            resetViewBeforeLoading = true;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder resetViewBeforeLoading(boolean resetViewBeforeLoading) {
            this.resetViewBeforeLoading = resetViewBeforeLoading;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        @Deprecated
        public Builder cacheInMemory() {
            cacheInMemory = true;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder cacheInMemory(boolean cacheInMemory) {
            this.cacheInMemory = cacheInMemory;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        @Deprecated
        public Builder cacheOnDisc() {
            return cacheOnDisk(true);
        }
        /**
         * 设置参数字段参考上面注释
         */
        @Deprecated
        public Builder cacheOnDisc(boolean cacheOnDisk) {
            return cacheOnDisk(cacheOnDisk);
        }
        /**
         * S设置参数字段参考上面注释
         */
        public Builder cacheOnDisk(boolean cacheOnDisk) {
            this.cacheOnDisk = cacheOnDisk;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder imageScaleType(ImageScaleType imageScaleType) {
            this.imageScaleType = imageScaleType;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder bitmapConfig(Bitmap.Config bitmapConfig) {
            if (bitmapConfig == null)
                throw new IllegalArgumentException("bitmapConfig can't be null");
            decodingOptions.inPreferredConfig = bitmapConfig;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder decodingOptions(Options decodingOptions) {
            if (decodingOptions == null)
                throw new IllegalArgumentException("decodingOptions can't be null");
            this.decodingOptions = decodingOptions;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder delayBeforeLoading(int delayInMillis) {
            this.delayBeforeLoading = delayInMillis;
            return this;
        }
        public Builder extraForDownloader(Object extra) {
            this.extraForDownloader = extra;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder considerExifParams(boolean considerExifParams) {
            this.considerExifParams = considerExifParams;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder preProcessor(BitmapProcessor preProcessor) {
            this.preProcessor = preProcessor;
            return this;
        }

        /**
         * 设置参数字段参考上面注释
         */
        public Builder postProcessor(BitmapProcessor postProcessor) {
            this.postProcessor = postProcessor;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder displayer(BitmapDisplayer displayer) {
            if (displayer == null) throw new IllegalArgumentException("displayer can't be null");
            this.displayer = displayer;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        Builder syncLoading(boolean isSyncLoading) {
            this.isSyncLoading = isSyncLoading;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public Builder handler(Handler handler) {
            this.handler = handler;
            return this;
        }
        /**
         * Sets all options equal to incoming options
         */
        public Builder cloneFrom(DisplayImageOptions options) {
            imageResOnLoading = options.imageResOnLoading;
            imageResForEmptyUri = options.imageResForEmptyUri;
            imageResOnFail = options.imageResOnFail;
            imageOnLoading = options.imageOnLoading;
            imageForEmptyUri = options.imageForEmptyUri;
            imageOnFail = options.imageOnFail;
            resetViewBeforeLoading = options.resetViewBeforeLoading;
            cacheInMemory = options.cacheInMemory;
            cacheOnDisk = options.cacheOnDisk;
            imageScaleType = options.imageScaleType;
            decodingOptions = options.decodingOptions;
            delayBeforeLoading = options.delayBeforeLoading;
            considerExifParams = options.considerExifParams;
            extraForDownloader = options.extraForDownloader;
            preProcessor = options.preProcessor;
            postProcessor = options.postProcessor;
            displayer = options.displayer;
            handler = options.handler;
            isSyncLoading = options.isSyncLoading;
            return this;
        }
        /**
         * 设置参数字段参考上面注释
         */
        public DisplayImageOptions build() {
            return new DisplayImageOptions(this);
        }
    }
    /**
     * 创建一个简单的参数类型
     */
    public static DisplayImageOptions createSimple() {
        return new Builder().build();
    }
}

(5)ImageLoaderConfiguration

这个类我们也是比较熟悉的,因为要使用ImageLoader的时候,我们第一个就是要配置这个参数,我们先来看一下常用的配置手法如下

public static void initImageLoader(Context context) {  
    File cacheDir = StorageUtils.getOwnCacheDirectory(context,  
            "bee_k77/Cache");// 获取到缓存的目录地址  
    Log.e("cacheDir", cacheDir.getPath());  
    // 创建配置ImageLoader(所有的选项都是可选的,只使用那些你真的想定制),这个可以设定在APPLACATION里面,设置为全局的配置参数  
    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(  
            context)  
            // max width, max height,即保存的每个缓存文件的最大长宽  
            .memoryCacheExtraOptions(480, 800)  
            // Can slow ImageLoader, use it carefully (Better don't use it)设置缓存的详细信息,最好不要设置这个  
/                .discCacheExtraOptions(480, 800, CompressFormat.JPEG, 75, null)   
            // 线程池内加载的数量  
            .threadPoolSize(3)  
            // 线程优先级  
            .threadPriority(Thread.NORM_PRIORITY - 2)  
            /* 
             * When you display an image in a small ImageView 
             *  and later you try to display this image (from identical URI) in a larger ImageView  
             *  so decoded image of bigger size will be cached in memory as a previous decoded image of smaller size. 
             *  So the default behavior is to allow to cache multiple sizes of one image in memory.  
             *  You can deny it by calling this method:  
             *  so when some image will be cached in memory then previous cached size of this image (if it exists) 
             *   will be removed from memory cache before. 
             */  
/               .denyCacheImageMultipleSizesInMemory()  

            // You can pass your own memory cache implementation你可以通过自己的内存缓存实现  
            // .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024))   
            // .memoryCacheSize(2 * 1024 * 1024)  
            //硬盘缓存50MB  
            .diskCacheSize(50 * 1024 * 1024)  
             //将保存的时候的URI名称用MD5  
            .diskCacheFileNameGenerator(new Md5FileNameGenerator())  
            // 加密  
             .diskCacheFileNameGenerator(new HashCodeFileNameGenerator())//将保存的时候的URI名称用HASHCODE加密  
            .tasksProcessingOrder(QueueProcessingType.LIFO)  
             .diskCacheFileCount(100) //缓存的File数量  
            .diskCache(new UnlimitedDiscCache(cacheDir))// 自定义缓存路径  
            // .defaultDisplayImageOptions(DisplayImageOptions.createSimple())  
            // .imageDownloader(new BaseImageDownloader(context, 5 * 1000,  
            // 30 * 1000)) // connectTimeout (5 s), readTimeout (30 s)超时时间  
            .writeDebugLogs() // Remove for release app  
            .build();  
    // Initialize ImageLoader with configuration.  
    ImageLoader.getInstance().init(config);// 全局初始化此配置  
}  

我们可以清楚看到建造者模式和链式调用的身影,接下来我们来看一下源码的实现。

public final class ImageLoaderConfiguration {

    final Resources resources;

    final int maxImageWidthForMemoryCache;//
    final int maxImageHeightForMemoryCache;
    final int maxImageWidthForDiskCache;//最大图片
    final int maxImageHeightForDiskCache;
    final BitmapProcessor processorForDiskCache;

    final Executor taskExecutor;
    final Executor taskExecutorForCachedImages;
    final boolean customExecutor;
    final boolean customExecutorForCachedImages;

    final int threadPoolSize;
    final int threadPriority;
    final QueueProcessingType tasksProcessingType;

    final MemoryCache memoryCache;
    final DiskCache diskCache;
    final ImageDownloader downloader;
    final ImageDecoder decoder;
    final DisplayImageOptions defaultDisplayImageOptions;

    final ImageDownloader networkDeniedDownloader;
    final ImageDownloader slowNetworkDownloader;

    private ImageLoaderConfiguration(final Builder builder) {
        resources = builder.context.getResources();
        maxImageWidthForMemoryCache = builder.maxImageWidthForMemoryCache;
        maxImageHeightForMemoryCache = builder.maxImageHeightForMemoryCache;
        maxImageWidthForDiskCache = builder.maxImageWidthForDiskCache;
        maxImageHeightForDiskCache = builder.maxImageHeightForDiskCache;
        processorForDiskCache = builder.processorForDiskCache;
        taskExecutor = builder.taskExecutor;
        taskExecutorForCachedImages = builder.taskExecutorForCachedImages;
        threadPoolSize = builder.threadPoolSize;
        threadPriority = builder.threadPriority;
        tasksProcessingType = builder.tasksProcessingType;
        diskCache = builder.diskCache;
        memoryCache = builder.memoryCache;
        defaultDisplayImageOptions = builder.defaultDisplayImageOptions;
        downloader = builder.downloader;
        decoder = builder.decoder;

        customExecutor = builder.customExecutor;
        customExecutorForCachedImages = builder.customExecutorForCachedImages;

        networkDeniedDownloader = new NetworkDeniedImageDownloader(downloader);
        slowNetworkDownloader = new SlowNetworkImageDownloader(downloader);

    }

    /**
     * 初始化一个空
     */
    public static ImageLoaderConfiguration createDefault(Context context) {
        return new Builder(context).build();
    }

    ImageSize getMaxImageSize() {
        DisplayMetrics displayMetrics = resources.getDisplayMetrics();

        int width = maxImageWidthForMemoryCache;
        if (width <= 0) {
            width = displayMetrics.widthPixels;
        }
        int height = maxImageHeightForMemoryCache;
        if (height <= 0) {
            height = displayMetrics.heightPixels;
        }
        return new ImageSize(width, height);
    }

    /**
     * Builder for {@link ImageLoaderConfiguration}
     *
     * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
     */
    public static class Builder {

        private static final String WARNING_OVERLAP_DISK_CACHE_PARAMS = "diskCache(), diskCacheSize() and diskCacheFileCount calls overlap each other";
        private static final String WARNING_OVERLAP_DISK_CACHE_NAME_GENERATOR = "diskCache() and diskCacheFileNameGenerator() calls overlap each other";
        private static final String WARNING_OVERLAP_MEMORY_CACHE = "memoryCache() and memoryCacheSize() calls overlap each other";
        private static final String WARNING_OVERLAP_EXECUTOR = "threadPoolSize(), threadPriority() and tasksProcessingOrder() calls "
                + "can overlap taskExecutor() and taskExecutorForCachedImages() calls.";

        /**
         * {@value}
         */
        public static final int DEFAULT_THREAD_POOL_SIZE = 3;
        /**
         * {@value}
         */
        public static final int DEFAULT_THREAD_PRIORITY = Thread.NORM_PRIORITY - 2;
        /**
         * {@value}
         */
        public static final QueueProcessingType DEFAULT_TASK_PROCESSING_TYPE = QueueProcessingType.FIFO;

        private Context context;

        private int maxImageWidthForMemoryCache = 0;
        private int maxImageHeightForMemoryCache = 0;
        private int maxImageWidthForDiskCache = 0;
        private int maxImageHeightForDiskCache = 0;
        private BitmapProcessor processorForDiskCache = null;

        private Executor taskExecutor = null;
        private Executor taskExecutorForCachedImages = null;
        private boolean customExecutor = false;
        private boolean customExecutorForCachedImages = false;

        private int threadPoolSize = DEFAULT_THREAD_POOL_SIZE;
        private int threadPriority = DEFAULT_THREAD_PRIORITY;
        private boolean denyCacheImageMultipleSizesInMemory = false;
        private QueueProcessingType tasksProcessingType = DEFAULT_TASK_PROCESSING_TYPE;

        private int memoryCacheSize = 0;
        private long diskCacheSize = 0;
        private int diskCacheFileCount = 0;

        private MemoryCache memoryCache = null;
        private DiskCache diskCache = null;
        private FileNameGenerator diskCacheFileNameGenerator = null;
        private ImageDownloader downloader = null;
        private ImageDecoder decoder;
        private DisplayImageOptions defaultDisplayImageOptions = null;

        private boolean writeLogs = false;

        public Builder(Context context) {
            this.context = context.getApplicationContext();
        }

        /**即保存的每个缓存文件的最大长宽
         */
        public Builder memoryCacheExtraOptions(int maxImageWidthForMemoryCache, int maxImageHeightForMemoryCache) {
            this.maxImageWidthForMemoryCache = maxImageWidthForMemoryCache;
            this.maxImageHeightForMemoryCache = maxImageHeightForMemoryCache;
            return this;
        }

        /**
         */
        @Deprecated
        public Builder discCacheExtraOptions(int maxImageWidthForDiskCache, int maxImageHeightForDiskCache,
                                             BitmapProcessor processorForDiskCache) {
            return diskCacheExtraOptions(maxImageWidthForDiskCache, maxImageHeightForDiskCache, processorForDiskCache);
        }

        /**
         */
        public Builder diskCacheExtraOptions(int maxImageWidthForDiskCache, int maxImageHeightForDiskCache,
                                             BitmapProcessor processorForDiskCache) {
            this.maxImageWidthForDiskCache = maxImageWidthForDiskCache;
            this.maxImageHeightForDiskCache = maxImageHeightForDiskCache;
            this.processorForDiskCache = processorForDiskCache;
            return this;
        }

        /**
         */
        public Builder taskExecutor(Executor executor) {
            if (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) {
            }
            this.taskExecutor = executor;
            return this;
        }

        /**
         */
        public Builder taskExecutorForCachedImages(Executor executorForCachedImages) {
            if (threadPoolSize != DEFAULT_THREAD_POOL_SIZE || threadPriority != DEFAULT_THREAD_PRIORITY || tasksProcessingType != DEFAULT_TASK_PROCESSING_TYPE) {
            }
            this.taskExecutorForCachedImages = executorForCachedImages;
            return this;
        }

        /**
         *  // 线程池内加载的数量
         */
        public Builder threadPoolSize(int threadPoolSize) {
            if (taskExecutor != null || taskExecutorForCachedImages != null) {
            }
            this.threadPoolSize = threadPoolSize;
            return this;
        }

        /**
         // 线程优先级
         */
        public Builder threadPriority(int threadPriority) {
            if (taskExecutor != null || taskExecutorForCachedImages != null) {
            }

            if (threadPriority < Thread.MIN_PRIORITY) {
                this.threadPriority = Thread.MIN_PRIORITY;
            } else {
                if (threadPriority > Thread.MAX_PRIORITY) {
                    this.threadPriority = Thread.MAX_PRIORITY;
                } else {
                    this.threadPriority = threadPriority;
                }
            }
            return this;
        }

        /**
         */
        public Builder denyCacheImageMultipleSizesInMemory() {
            this.denyCacheImageMultipleSizesInMemory = true;
            return this;
        }

        /**
         * 设置处理队列类型
         * Default value - {@link QueueProcessingType#FIFO}
         */
        public Builder tasksProcessingOrder(QueueProcessingType tasksProcessingType) {
            if (taskExecutor != null || taskExecutorForCachedImages != null) {
            }

            this.tasksProcessingType = tasksProcessingType;
            return this;
        }

        /**

         */
        public Builder memoryCacheSize(int memoryCacheSize) {
            if (memoryCacheSize <= 0)
                throw new IllegalArgumentException("memoryCacheSize must be a positive number");

            if (memoryCache != null) {
            }

            this.memoryCacheSize = memoryCacheSize;
            return this;
        }

        /**
         * Sets maximum memory cache size (in percent of available app memory) for {@link android.graphics.Bitmap
         * bitmaps}.<br />
         * Default value - 1/8 of available app memory.<br />
         * <b>NOTE:</b> If you use this method then
         * memory cache. You can use {@link #memoryCache(MemoryCache)} method to set your own implementation of
         * {@link MemoryCache}.
         */
        public Builder memoryCacheSizePercentage(int availableMemoryPercent) {
            if (availableMemoryPercent <= 0 || availableMemoryPercent >= 100) {
                throw new IllegalArgumentException("availableMemoryPercent must be in range (0 < % < 100)");
            }

            if (memoryCache != null) {
            }

            long availableMemory = Runtime.getRuntime().maxMemory();
            memoryCacheSize = (int) (availableMemory * (availableMemoryPercent / 100f));
            return this;
        }

        /**
         * Sets memory cache for {@link android.graphics.Bitmap bitmaps}.<br />
         * with limited memory cache size (size = 1/8 of available app memory)<br />
         * <br />
         * <b>NOTE:</b> If you set custom memory cache then following configuration option will not be considered:
         * <ul>
         * <li>{@link #memoryCacheSize(int)}</li>
         * </ul>
         */
        public Builder memoryCache(MemoryCache memoryCache) {
            if (memoryCacheSize != 0) {
            }

            this.memoryCache = memoryCache;
            return this;
        }

        /**
         //硬盘缓存50MB
         */
        @Deprecated
        public Builder discCacheSize(int maxCacheSize) {
            return diskCacheSize(maxCacheSize);
        }

        /**

         */
        public Builder diskCacheSize(int maxCacheSize) {
            if (maxCacheSize <= 0)
                throw new IllegalArgumentException("maxCacheSize must be a positive number");

            if (diskCache != null) {
            }

            this.diskCacheSize = maxCacheSize;
            return this;
        }

        /**
         * @deprecated Use {@link #diskCacheFileCount(int)} instead
         */
        @Deprecated
        public Builder discCacheFileCount(int maxFileCount) {
            return diskCacheFileCount(maxFileCount);
        }

        /**
         * Sets maximum file count in disk cache directory.<br />
         * By default: disk cache is unlimited.<br />
         * <b>NOTE:</b> If you use this method then
         * will be used as disk cache. You can use {@link #diskCache(DiskCache)} method for introduction your own
         * implementation of {@link DiskCache}
         */
        public Builder diskCacheFileCount(int maxFileCount) {
            if (maxFileCount <= 0)
                throw new IllegalArgumentException("maxFileCount must be a positive number");

            if (diskCache != null) {
            }

            this.diskCacheFileCount = maxFileCount;
            return this;
        }

        /**  //将保存的时候的URI名称用MD5
         */
        @Deprecated
        public Builder discCacheFileNameGenerator(FileNameGenerator fileNameGenerator) {
            return diskCacheFileNameGenerator(fileNameGenerator);
        }

        /**
         * Sets name generator for files cached in disk cache.<br />
         * Default value -
         * DefaultConfigurationFactory.createFileNameGenerator()}
         */
        public Builder diskCacheFileNameGenerator(FileNameGenerator fileNameGenerator) {
            if (diskCache != null) {
            }

            this.diskCacheFileNameGenerator = fileNameGenerator;
            return this;
        }

        /**
         */
        @Deprecated
        public Builder discCache(DiskCache diskCache) {
            return diskCache(diskCache);
        }

        /**
         设置磁盘缓存策略
         */
        public Builder diskCache(DiskCache diskCache) {
            if (diskCacheSize > 0 || diskCacheFileCount > 0) {
            }
            if (diskCacheFileNameGenerator != null) {
            }
            this.diskCache = diskCache;
            return this;
        }

        /**
         设置图片下载器
         */
        public Builder imageDownloader(ImageDownloader imageDownloader) {
            this.downloader = imageDownloader;
            return this;
        }

        /**
         设置图片展示器
         */
        public Builder imageDecoder(ImageDecoder imageDecoder) {
            this.decoder = imageDecoder;
            return this;
        }

        /**
         设置默认的图片展示操作参数
         */
        public Builder defaultDisplayImageOptions(DisplayImageOptions defaultDisplayImageOptions) {
            this.defaultDisplayImageOptions = defaultDisplayImageOptions;
            return this;
        }

        /**是否写日志
         */
        public Builder writeDebugLogs() {
            this.writeLogs = true;
            return this;
        }

        /**
         * Builds configured {@link ImageLoaderConfiguration} object
         */
        public ImageLoaderConfiguration build() {
            initEmptyFieldsWithDefaultValues();
            return new ImageLoaderConfiguration(this);
        }

        private void initEmptyFieldsWithDefaultValues() {
            if (taskExecutor == null) {      //初始化一个默认
                taskExecutor = DefaultConfigurationFactory
                        .createExecutor(threadPoolSize, threadPriority, tasksProcessingType);
            } else {
                customExecutor = true;
            }
            if (taskExecutorForCachedImages == null) { //初始化一个
                taskExecutorForCachedImages = DefaultConfigurationFactory
                        .createExecutor(threadPoolSize, threadPriority, tasksProcessingType);
            } else {
                customExecutorForCachedImages = true;
            }
            if (diskCache == null) {//初始化文件名生成器
                if (diskCacheFileNameGenerator == null) {
                    diskCacheFileNameGenerator = DefaultConfigurationFactory.createFileNameGenerator();
                }

                //初始化化一个磁盘缓存策略
                diskCache = DefaultConfigurationFactory
                        .createDiskCache(context, diskCacheFileNameGenerator, diskCacheSize, diskCacheFileCount);
            }

            //初始化一个内存缓存策略
            if (memoryCache == null) {
                memoryCache = DefaultConfigurationFactory.createMemoryCache(context, memoryCacheSize);
            }
            if (denyCacheImageMultipleSizesInMemory) {
                memoryCache = new FuzzyKeyMemoryCache(memoryCache, MemoryCacheUtils.createFuzzyKeyComparator());
            }
            if (downloader == null) {//初始化一个图片下载器
                downloader = DefaultConfigurationFactory.createImageDownloader(context);
            }
            if (decoder == null) { //初始化一个图片修饰器
                decoder = DefaultConfigurationFactory.createImageDecoder(writeLogs);
            }
            if (defaultDisplayImageOptions == null) { //初始化一个图片加载参数
                defaultDisplayImageOptions = DisplayImageOptions.createSimple();
            }
        }
    }

    /**
    网络图片下载器
     */
    private static class NetworkDeniedImageDownloader implements ImageDownloader {

        private final ImageDownloader wrappedDownloader;

        public NetworkDeniedImageDownloader(ImageDownloader wrappedDownloader) {
            this.wrappedDownloader = wrappedDownloader;
        }

        @Override
        public InputStream getStream(String imageUri, Object extra) throws IOException {
            switch (Scheme.ofUri(imageUri)) {
                case HTTP:
                case HTTPS:
                    throw new IllegalStateException();
                default:
                    return wrappedDownloader.getStream(imageUri, extra);
            }
        }
    }

    /**
     * 网络慢的时候使用一个流刷
     */
    private static class SlowNetworkImageDownloader implements ImageDownloader {

        private final ImageDownloader wrappedDownloader;

        public SlowNetworkImageDownloader(ImageDownloader wrappedDownloader) {
            this.wrappedDownloader = wrappedDownloader;
        }

        @Override
        public InputStream getStream(String imageUri, Object extra) throws IOException {
            InputStream imageStream = wrappedDownloader.getStream(imageUri, extra);
            switch (Scheme.ofUri(imageUri)) {
                case HTTP:
                case HTTPS:
                    return new FlushedInputStream(imageStream);
                default:
                    return imageStream;
            }
        }
    }
}

(6)ImageLoaderEngine

这是一个负责将图片加载任务分发到各个线程执行的类

/*******************************************************************************
 * Copyright 2011-2014 Sergey Tarasevich
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package leakcanary.imageloader.core;

import java.io.File;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;

import leakcanary.imageloader.core.imageaware.ImageAware;

/**
 *负责将图片加载任务分发到各个线程执行。
 */
class ImageLoaderEngine {

    final ImageLoaderConfiguration configuration;//配置信息

    private Executor taskExecutor;//执行从源获取图片任务的executor
    private Executor taskExecutorForCachedImages;//执行从缓存获取图片任务的executor
    private Executor taskDistributor;//任务分发池

    private final Map<Integer, String> cacheKeysForImageAwares = Collections
            .synchronizedMap(new HashMap<Integer, String>());
    private final Map<String, ReentrantLock> uriLocks = new WeakHashMap<String, ReentrantLock>();

    private final AtomicBoolean paused = new AtomicBoolean(false);//是否暂停执行任务
    private final AtomicBoolean networkDenied = new AtomicBoolean(false);//是否拒绝网络访问
    private final AtomicBoolean slowNetwork = new AtomicBoolean(false);//是否是慢网络情况

    private final Object pauseLock = new Object();//暂停等待锁
     //初始化
    ImageLoaderEngine(ImageLoaderConfiguration configuration) {
        this.configuration = configuration;

        taskExecutor = configuration.taskExecutor;
        taskExecutorForCachedImages = configuration.taskExecutorForCachedImages;

        taskDistributor = DefaultConfigurationFactory.createTaskDistributor();
    }

    //提交LoadAndDisplayImageTask任务
    void submit(final LoadAndDisplayImageTask task) {
        taskDistributor.execute(new Runnable() {
            @Override
            public void run() {
                File image = configuration.diskCache.get(task.getLoadingUri());
                boolean isImageCachedOnDisk = image != null && image.exists();
                initExecutorsIfNeed();
                if (isImageCachedOnDisk) {
                    taskExecutorForCachedImages.execute(task);
                } else {
                    taskExecutor.execute(task);
                }
            }
        });
    }

    /** 直接交由taskExecutorForCachedImages执行。 */
    void submit(ProcessAndDisplayImageTask task) {
        initExecutorsIfNeed();
        taskExecutorForCachedImages.execute(task);
    }

    private void initExecutorsIfNeed() {
        if (!configuration.customExecutor && ((ExecutorService) taskExecutor).isShutdown()) {
            taskExecutor = createTaskExecutor();
        }
        if (!configuration.customExecutorForCachedImages && ((ExecutorService) taskExecutorForCachedImages)
                .isShutdown()) {
            taskExecutorForCachedImages = createTaskExecutor();
        }
    }

    private Executor createTaskExecutor() {
        return DefaultConfigurationFactory
                .createExecutor(configuration.threadPoolSize, configuration.threadPriority,
                configuration.tasksProcessingType);
    }

    /**
     */
    String getLoadingUriForView(ImageAware imageAware) {
        return cacheKeysForImageAwares.get(imageAware.getId());
    }

    /**
     * Associates <b>memoryCacheKey</b> with <b>imageAware</b>. Then it helps to define image URI is loaded into View at
     * exact moment.
     */
    void prepareDisplayTaskFor(ImageAware imageAware, String memoryCacheKey) {
        cacheKeysForImageAwares.put(imageAware.getId(), memoryCacheKey);
    }

    /**
     * Cancels the task of loading and displaying image for incoming <b>imageAware</b>.
     *
     *                   will be cancelled
     */
    void cancelDisplayTaskFor(ImageAware imageAware) {
        cacheKeysForImageAwares.remove(imageAware.getId());
    }

    /**
     * Denies or allows engine to download images from the network.<br /> <br /> If downloads are denied and if image
     *
     * @param denyNetworkDownloads pass <b>true</b> - to deny engine to download images from the network; <b>false</b> -
     *                             to allow engine to download images from network.
     */
    void denyNetworkDownloads(boolean denyNetworkDownloads) {
        networkDenied.set(denyNetworkDownloads);
    }

    /**
     * href="http://code.google.com/p/android/issues/detail?id=6066">this known problem</a> or not.
     *
     *                          - otherwise.
     */
    void handleSlowNetwork(boolean handleSlowNetwork) {
        slowNetwork.set(handleSlowNetwork);
    }

    /**
     * Pauses engine. All new "load&display" tasks won't be executed until ImageLoader is {@link #resume() resumed}.<br
     * /> Already running tasks are not paused.
     */
    void pause() {
        paused.set(true);
    }

    /** Resumes engine work. Paused "load&display" tasks will continue its work. */
    void resume() {
        paused.set(false);
        synchronized (pauseLock) {
            pauseLock.notifyAll();
        }
    }

    /**
     * Stops engine, cancels all running and scheduled display image tasks. Clears internal data.
     * <br />
     * <b>NOTE:</b> This method doesn't shutdown
     * custom task executors} if you set them.
     */
    void stop() {
        if (!configuration.customExecutor) {
            ((ExecutorService) taskExecutor).shutdownNow();
        }
        if (!configuration.customExecutorForCachedImages) {
            ((ExecutorService) taskExecutorForCachedImages).shutdownNow();
        }

        cacheKeysForImageAwares.clear();
        uriLocks.clear();
    }

    void fireCallback(Runnable r) {
        taskDistributor.execute(r);
    }

    ReentrantLock getLockForUri(String uri) {
        ReentrantLock lock = uriLocks.get(uri);
        if (lock == null) {
            lock = new ReentrantLock();
            uriLocks.put(uri, lock);
        }
        return lock;
    }

    AtomicBoolean getPause() {
        return paused;
    }

    Object getPauseLock() {
        return pauseLock;
    }

    boolean isNetworkDenied() {
        return networkDenied.get();
    }

    boolean isSlowNetwork() {
        return slowNetwork.get();
    }
}

(7)ImageLoadingInfo 一个展示和下载的实体类包含多种内容

final class ImageLoadingInfo {

    final String uri;//地址
    final String memoryCacheKey;//内存缓存的键
    final ImageAware imageAware;//imageview
    final ImageSize targetSize;//目标大小
    final DisplayImageOptions options;//图片操作
    final ImageLoadingListener listener;//图片下载监听器
    final ImageLoadingProgressListener progressListener;//图片处理监听器
    final ReentrantLock loadFromUriLock;//锁
    //构造方法
    public ImageLoadingInfo(String uri, ImageAware imageAware, ImageSize targetSize, String memoryCacheKey,
                            DisplayImageOptions options, ImageLoadingListener listener,
                            ImageLoadingProgressListener progressListener, ReentrantLock loadFromUriLock) {
        this.uri = uri;
        this.imageAware = imageAware;
        this.targetSize = targetSize;
        this.options = options;
        this.listener = listener;
        this.progressListener = progressListener;
        this.loadFromUriLock = loadFromUriLock;
        this.memoryCacheKey = memoryCacheKey;
    }
}

(8)ProcessAndDisplayImageTask

对象交给ProcessAndDisplayImageTask,见名知意,这个对象就是使ImageView显示图片的,是一个Ruannable。

final class ProcessAndDisplayImageTask implements Runnable {
    private static final String LOG_POSTPROCESS_IMAGE = "PostProcess image before displaying [%s]";
    private final ImageLoaderEngine engine;
    private final Bitmap bitmap;
    private final ImageLoadingInfo imageLoadingInfo;
    private final Handler handler;

    public ProcessAndDisplayImageTask(ImageLoaderEngine engine, Bitmap bitmap, ImageLoadingInfo imageLoadingInfo,
            Handler handler) {
        this.engine = engine;
        this.bitmap = bitmap;
        this.imageLoadingInfo = imageLoadingInfo;
        this.handler = handler;
    }

    @Override
    public void run() {
        BitmapProcessor processor = imageLoadingInfo.options.getPostProcessor();
        Bitmap processedBitmap = processor.process(bitmap);
        DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(processedBitmap, imageLoadingInfo, engine,
                LoadedFrom.MEMORY_CACHE);
        LoadAndDisplayImageTask.runTask(displayBitmapTask, imageLoadingInfo.options.isSyncLoading(), handler, engine);
    }
}
/**对象交给ProcessAndDisplayImageTask,见名知意,这个对象就是使ImageView显示图片的,是一个Ruannable。
 */
final class ProcessAndDisplayImageTask implements Runnable {
    private static final String LOG_POSTPROCESS_IMAGE = "PostProcess image before displaying [%s]";
    private final ImageLoaderEngine engine;
    private final Bitmap bitmap;
    private final ImageLoadingInfo imageLoadingInfo;
    private final Handler handler;
    public ProcessAndDisplayImageTask(ImageLoaderEngine engine, Bitmap bitmap, ImageLoadingInfo imageLoadingInfo,
            Handler handler) {
        this.engine = engine;
        this.bitmap = bitmap;
        this.imageLoadingInfo = imageLoadingInfo;
        this.handler = handler;
    }
    @Override
    public void run() {
        //获取DisplayImageOptions配置的BitmapProcessor 对象
        BitmapProcessor processor = imageLoadingInfo.options.getPostProcessor();
//      执行BitmapProcessor 的process方法对Bitmap进行加工处理
        Bitmap processedBitmap = processor.process(bitmap);
//      将加工过的Bitmap传给DisplayBitmapTask对象,该对象也是一个Runnable。
            DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(processedBitmap, imageLoadingInfo, engine,
                LoadedFrom.MEMORY_CACHE);
        //真正展示的方法
        LoadAndDisplayImageTask.runTask(displayBitmapTask, imageLoadingInfo.options.isSyncLoading(), handler, engine);
    }
}

(9)LoadAndDisplayImageTask

这个是一个图片下载展示的类,继承runnable,是为了三级缓存用

final class LoadAndDisplayImageTask implements Runnable, IoUtils.CopyListener {

    private static final String LOG_WAITING_FOR_RESUME = "ImageLoader is paused. Waiting...  [%s]";
    private static final String LOG_RESUME_AFTER_PAUSE = ".. Resume loading [%s]";
    private static final String LOG_DELAY_BEFORE_LOADING = "Delay %d ms before loading...  [%s]";
    private static final String LOG_START_DISPLAY_IMAGE_TASK = "Start display image task [%s]";
    private static final String LOG_WAITING_FOR_IMAGE_LOADED = "Image already is loading. Waiting... [%s]";
    private static final String LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING = "...Get cached bitmap from memory after waiting. [%s]";
    private static final String LOG_LOAD_IMAGE_FROM_NETWORK = "Load image from network [%s]";
    private static final String LOG_LOAD_IMAGE_FROM_DISK_CACHE = "Load image from disk cache [%s]";
    private static final String LOG_RESIZE_CACHED_IMAGE_FILE = "Resize image in disk cache [%s]";
    private static final String LOG_PREPROCESS_IMAGE = "PreProcess image before caching in memory [%s]";
    private static final String LOG_POSTPROCESS_IMAGE = "PostProcess image before displaying [%s]";
    private static final String LOG_CACHE_IMAGE_IN_MEMORY = "Cache image in memory [%s]";
    private static final String LOG_CACHE_IMAGE_ON_DISK = "Cache image on disk [%s]";
    private static final String LOG_PROCESS_IMAGE_BEFORE_CACHE_ON_DISK = "Process image before cache on disk [%s]";
    private static final String LOG_TASK_CANCELLED_IMAGEAWARE_REUSED = "ImageAware is reused for another image. Task is cancelled. [%s]";
    private static final String LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED = "ImageAware was collected by GC. Task is cancelled. [%s]";
    private static final String LOG_TASK_INTERRUPTED = "Task was interrupted [%s]";

    private static final String ERROR_NO_IMAGE_STREAM = "No stream for image [%s]";
    private static final String ERROR_PRE_PROCESSOR_NULL = "Pre-processor returned null [%s]";
    private static final String ERROR_POST_PROCESSOR_NULL = "Post-processor returned null [%s]";
    private static final String ERROR_PROCESSOR_FOR_DISK_CACHE_NULL = "Bitmap processor for disk cache returned null [%s]";

    private final ImageLoaderEngine engine;
    private final ImageLoadingInfo imageLoadingInfo;
    private final Handler handler;

    // Helper references
    private final ImageLoaderConfiguration configuration;
    private final ImageDownloader downloader;
    private final ImageDownloader networkDeniedDownloader;
    private final ImageDownloader slowNetworkDownloader;
    private final ImageDecoder decoder;
    final String uri;
    private final String memoryCacheKey;
    final ImageAware imageAware;
    private final ImageSize targetSize;
    final DisplayImageOptions options;
    final ImageLoadingListener listener;
    final ImageLoadingProgressListener progressListener;
    private final boolean syncLoading;

    // State vars
    private LoadedFrom loadedFrom = LoadedFrom.NETWORK;

    //初始化
    public LoadAndDisplayImageTask(ImageLoaderEngine engine, ImageLoadingInfo imageLoadingInfo, Handler handler) {
        this.engine = engine;
        this.imageLoadingInfo = imageLoadingInfo;
        this.handler = handler;

        configuration = engine.configuration;
        downloader = configuration.downloader;
        networkDeniedDownloader = configuration.networkDeniedDownloader;
        slowNetworkDownloader = configuration.slowNetworkDownloader;
        decoder = configuration.decoder;
        uri = imageLoadingInfo.uri;
        memoryCacheKey = imageLoadingInfo.memoryCacheKey;
        imageAware = imageLoadingInfo.imageAware;
        targetSize = imageLoadingInfo.targetSize;
        options = imageLoadingInfo.options;
        listener = imageLoadingInfo.listener;
        progressListener = imageLoadingInfo.progressListener;
        syncLoading = options.isSyncLoading();
    }

    //跑起来
    @Override
    public void run() {
        if (waitIfPaused()) return;//如果需要等待
        if (delayIfNeed()) return;//如果需要延迟
        //加一个锁
        ReentrantLock loadFromUriLock = imageLoadingInfo.loadFromUriLock;
        L.d(LOG_START_DISPLAY_IMAGE_TASK, memoryCacheKey);
        if (loadFromUriLock.isLocked()) {
            L.d(LOG_WAITING_FOR_IMAGE_LOADED, memoryCacheKey);
        }

        loadFromUriLock.lock();
        Bitmap bmp;
        try {
            checkTaskNotActual();
            //从内存中获取
            bmp = configuration.memoryCache.get(memoryCacheKey);
            if (bmp == null || bmp.isRecycled()) {//如果没有内存
                bmp = tryLoadBitmap();//这个方法尝试从磁盘中拿到,磁盘没就从网络拿
                if (bmp == null) return; // listener callback already was fired

                checkTaskNotActual();
                checkTaskInterrupted();

                if (options.shouldPreProcess()) {  //是否应该预处理
                    L.d(LOG_PREPROCESS_IMAGE, memoryCacheKey);
                    bmp = options.getPreProcessor().process(bmp);//处理
                    if (bmp == null) {
                        L.e(ERROR_PRE_PROCESSOR_NULL, memoryCacheKey);
                    }
                }

                if (bmp != null && options.isCacheInMemory()) {//如果从内存拿的 放回去
                    L.d(LOG_CACHE_IMAGE_IN_MEMORY, memoryCacheKey);
                    configuration.memoryCache.put(memoryCacheKey, bmp);
                }
            } else {
                loadedFrom = LoadedFrom.MEMORY_CACHE;
                L.d(LOG_GET_IMAGE_FROM_MEMORY_CACHE_AFTER_WAITING, memoryCacheKey);
            }

            if (bmp != null && options.shouldPostProcess()) {//如果拿到了就处理
                L.d(LOG_POSTPROCESS_IMAGE, memoryCacheKey);
                bmp = options.getPostProcessor().process(bmp);
                if (bmp == null) {
                    L.e(ERROR_POST_PROCESSOR_NULL, memoryCacheKey);
                }
            }
            checkTaskNotActual();
            checkTaskInterrupted();
        } catch (TaskCancelledException e) {
            fireCancelEvent();
            return;
        } finally {
            loadFromUriLock.unlock();//关闭锁
        }
        //展示
        DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, imageLoadingInfo, engine, loadedFrom);
        runTask(displayBitmapTask, syncLoading, handler, engine);
    }

    /**
     * 是否应该等待
     */
    private boolean waitIfPaused() {
        AtomicBoolean pause = engine.getPause();
        if (pause.get()) {
            synchronized (engine.getPauseLock()) {
                if (pause.get()) {
                    L.d(LOG_WAITING_FOR_RESUME, memoryCacheKey);
                    try {
                        engine.getPauseLock().wait();
                    } catch (InterruptedException e) {
                        L.e(LOG_TASK_INTERRUPTED, memoryCacheKey);
                        return true;
                    }
                    L.d(LOG_RESUME_AFTER_PAUSE, memoryCacheKey);
                }
            }
        }
        return isTaskNotActual();
    }

    /**
     * 收应该延迟
     */
    private boolean delayIfNeed() {
        if (options.shouldDelayBeforeLoading()) {
            L.d(LOG_DELAY_BEFORE_LOADING, options.getDelayBeforeLoading(), memoryCacheKey);
            try {
                Thread.sleep(options.getDelayBeforeLoading());
            } catch (InterruptedException e) {
                L.e(LOG_TASK_INTERRUPTED, memoryCacheKey);
                return true;
            }
            return isTaskNotActual();
        }
        return false;
    }

    //尝试从磁盘拿到缓存,没有就请求网络
    private Bitmap tryLoadBitmap() throws TaskCancelledException {
        Bitmap bitmap = null;
        try {
            File imageFile = configuration.diskCache.get(uri);//拿到文件
            if (imageFile != null && imageFile.exists() && imageFile.length() > 0) {//文件不为空
                L.d(LOG_LOAD_IMAGE_FROM_DISK_CACHE, memoryCacheKey);
                loadedFrom = LoadedFrom.DISC_CACHE;//标识来源

                checkTaskNotActual();
                bitmap = decodeImage(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;
                if (options.isCacheOnDisk() && tryCacheImageOnDisk()) {
                    imageFile = configuration.diskCache.get(uri);
                    if (imageFile != null) {
                        imageUriForDecoding = 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;
    }

    //修饰
    private Bitmap decodeImage(String imageUri) throws IOException {
        ViewScaleType viewScaleType = imageAware.getScaleType();
        ImageDecodingInfo decodingInfo = new ImageDecodingInfo(memoryCacheKey, imageUri, uri, targetSize, viewScaleType,
                getDownloader(), options);
        return decoder.decode(decodingInfo);
    }

    /**
     * 尝试保存图片到缓存
     */
    private boolean tryCacheImageOnDisk() throws TaskCancelledException {
        L.d(LOG_CACHE_IMAGE_ON_DISK, memoryCacheKey);

        boolean loaded;
        try {
            loaded = downloadImage();
            if (loaded) {
                int width = configuration.maxImageWidthForDiskCache;
                int height = configuration.maxImageHeightForDiskCache;
                if (width > 0 || height > 0) {
                    L.d(LOG_RESIZE_CACHED_IMAGE_FILE, memoryCacheKey);
                    resizeAndSaveImage(width, height); // TODO : process boolean result
                }
            }
        } catch (IOException e) {
            L.e(e);
            loaded = false;
        }
        return loaded;
    }
          //下载图片
    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 {
                return configuration.diskCache.save(uri, is, this);
            } finally {
                IoUtils.closeSilently(is);
            }
        }
    }

    /**
     * 压缩图片保存图片
     */
    private boolean resizeAndSaveImage(int maxWidth, int maxHeight) throws IOException {
        // Decode image file, compress and re-save it
        boolean saved = false;
        File targetFile = configuration.diskCache.get(uri);
        if (targetFile != null && targetFile.exists()) {
            ImageSize targetImageSize = new ImageSize(maxWidth, maxHeight);
            DisplayImageOptions specialOptions = new DisplayImageOptions.Builder().cloneFrom(options)
                    .imageScaleType(ImageScaleType.IN_SAMPLE_INT).build();
            ImageDecodingInfo decodingInfo = new ImageDecodingInfo(memoryCacheKey,
                    FILE.wrap(targetFile.getAbsolutePath()), uri, targetImageSize, ViewScaleType.FIT_INSIDE,
                    getDownloader(), specialOptions);
            Bitmap bmp = decoder.decode(decodingInfo);
            if (bmp != null && configuration.processorForDiskCache != null) {
                L.d(LOG_PROCESS_IMAGE_BEFORE_CACHE_ON_DISK, memoryCacheKey);
                bmp = configuration.processorForDiskCache.process(bmp);
                if (bmp == null) {
                    L.e(ERROR_PROCESSOR_FOR_DISK_CACHE_NULL, memoryCacheKey);
                }
            }
            if (bmp != null) {
                saved = configuration.diskCache.save(uri, bmp);
                bmp.recycle();
            }
        }
        return saved;
    }

    @Override
    public boolean onBytesCopied(int current, int total) {
        return syncLoading || fireProgressEvent(current, total);
    }

    /**
     * @return <b>true</b> - if loading should be continued; <b>false</b> - if loading should be interrupted
     */
    private boolean fireProgressEvent(final int current, final int total) {
        if (isTaskInterrupted() || isTaskNotActual()) return false;
        if (progressListener != null) {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    progressListener.onProgressUpdate(uri, imageAware.getWrappedView(), current, total);
                }
            };
            runTask(r, false, handler, engine);
        }
        return true;
    }

    private void fireFailEvent(final FailType failType, final Throwable failCause) {
        if (syncLoading || isTaskInterrupted() || isTaskNotActual()) return;
        Runnable r = new Runnable() {
            @Override
            public void run() {
                if (options.shouldShowImageOnFail()) {
                    imageAware.setImageDrawable(options.getImageOnFail(configuration.resources));
                }
                listener.onLoadingFailed(uri, imageAware.getWrappedView(), new FailReason(failType, failCause));
            }
        };
        runTask(r, false, handler, engine);
    }

    private void fireCancelEvent() {
        if (syncLoading || isTaskInterrupted()) return;
        Runnable r = new Runnable() {
            @Override
            public void run() {
                listener.onLoadingCancelled(uri, imageAware.getWrappedView());
            }
        };
        runTask(r, false, handler, engine);
    }

    //拿到下载器
    private ImageDownloader getDownloader() {
        ImageDownloader d;
        if (engine.isNetworkDenied()) {
            d = networkDeniedDownloader;
        } else if (engine.isSlowNetwork()) {
            d = slowNetworkDownloader;
        } else {
            d = downloader;
        }
        return d;
    }

    /**判断是否被回收
     */
    private void checkTaskNotActual() throws TaskCancelledException {
        checkViewCollected();
        checkViewReused();
    }

    /**判断view是否被回收
     */
    private boolean isTaskNotActual() {
        return isViewCollected() || isViewReused();
    }

    /**
     * @throws TaskCancelledException if target ImageAware is collected
     */
    private void checkViewCollected() throws TaskCancelledException {
        if (isViewCollected()) {
            throw new TaskCancelledException();
        }
    }

    /**
     * ImageAare是否被回收
     */
    private boolean isViewCollected() {
        if (imageAware.isCollected()) {
            L.d(LOG_TASK_CANCELLED_IMAGEAWARE_COLLECTED, memoryCacheKey);
            return true;
        }
        return false;
    }

    /**
     * ImageAware。是否被回收
     */
    private void checkViewReused() throws TaskCancelledException {
        if (isViewReused()) {
            throw new TaskCancelledException();
        }
    }

    /**
     * imageAware是否被展示其他图片了
     */
    private boolean isViewReused() {
        String currentCacheKey = engine.getLoadingUriForView(imageAware);
        // Check whether memory cache key (image URI) for current ImageAware is actual.
        // If ImageAware is reused for another task then current task should be cancelled.
        boolean imageAwareWasReused = !memoryCacheKey.equals(currentCacheKey);
        if (imageAwareWasReused) {
            L.d(LOG_TASK_CANCELLED_IMAGEAWARE_REUSED, memoryCacheKey);
            return true;
        }
        return false;
    }

    /**
     * 检查任务是否被中断
     */
    private void checkTaskInterrupted() throws TaskCancelledException {
        if (isTaskInterrupted()) {
            throw new TaskCancelledException();
        }
    }

    /**
     * 检查任务是否被中断
     */
    private boolean isTaskInterrupted() {
        if (Thread.interrupted()) {
            L.d(LOG_TASK_INTERRUPTED, memoryCacheKey);
            return true;
        }
        return false;
    }

    //拿到uri
    String getLoadingUri() {
        return uri;
    }

    //运行任务
    static void runTask(Runnable r, boolean sync, Handler handler, ImageLoaderEngine engine) {
        if (sync) {
            r.run();
        } else if (handler == null) {
            engine.fireCallback(r);
        } else {
            handler.post(r);
        }
    }

    //异常类
    class TaskCancelledException extends Exception {
    }
}

三、其他辅助类讲解

好了讲完核心类,我们来看一下辅助类们的结构

这里写图片描述

(1)ImageLoadingListener,

我们先看一下监听相关的类,下面ImageLoadingListener定义了图片加载监听的接口,包括开始,下载失败,加载完成,加载取消,后面还有ImageLoadingProgressListener,这个监听是带有进度条的监听,下面还有接口的简单实现类SimpleImageLoadingListener,你可以自定义监听,实现上面的接口就可以了

/**
 * 图片加载的监听器接口
 */
public interface ImageLoadingListener {
    /**
     * 开始下载
     */
    void onLoadingStarted(String imageUri, View view);
    /**
     * 下载失败
     */
    void onLoadingFailed(String imageUri, View view, FailReason failReason);
    /**
     *加载完成
     */
    void onLoadingComplete(String imageUri, View view, Bitmap loadedImage);
    /**加载取消
     */
    void onLoadingCancelled(String imageUri, View view);
}
public interface ImageLoadingProgressListener {
    void onProgressUpdate(String imageUri, View view, int current, int total);
}
public class SimpleImageLoadingListener implements ImageLoadingListener {
    @Override
    public void onLoadingStarted(String imageUri, View view) {
        // Empty implementation
    }

    @Override
    public void onLoadingFailed(String imageUri, View view, FailReason failReason) {
        // Empty implementation
    }

    @Override
    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
        // Empty implementation
    }

    @Override
    public void onLoadingCancelled(String imageUri, View view) {
        // Empty implementation
    }
}

(2)接下来,我们看一下ImageAware这包,我们先看一下ImageAware这个接口定义

/**
 ImageAware的接口
 */
public interface ImageAware {
    /**拿到宽度
     */
    int getWidth();

    /**拿到高度
     */
    int getHeight();

    /**拿到缩放的类型
     */
    ViewScaleType getScaleType();

    /**
     */
    View getWrappedView();

    /**
     */
    boolean isCollected();

    /**
     */
    int getId();

    /**
     */
    boolean setImageDrawable(Drawable drawable);

    /**
     */
    boolean setImageBitmap(Bitmap bitmap);
}

然后我们看实现这个接口的抽象类ViewAware,主要是暴露两个抽象方法让子类去设置图片,还有就是提供一些获取和保存属性的方法

public abstract class ViewAware implements ImageAware {
    public static final String WARN_CANT_SET_DRAWABLE = "Can't set a drawable into view. You should call ImageLoader on UI thread for it.";
    public static final String WARN_CANT_SET_BITMAP = "Can't set a bitmap into view. You should call ImageLoader on UI thread for it.";
    protected Reference<View> viewRef;
    protected boolean checkActualViewSize;
    public ViewAware(View view) {
        this(view, true);
    }
    public ViewAware(View view, boolean checkActualViewSize) {
        if (view == null) throw new IllegalArgumentException("view must not be null");
        this.viewRef = new WeakReference<View>(view);//将传入的的View搞成弱引用
        this.checkActualViewSize = checkActualViewSize;//检查实际view大小
    }
    /**拿到View的宽
     */
    @Override
    public int getWidth() {
        View view = viewRef.get();
        if (view != null) {
            final ViewGroup.LayoutParams params = view.getLayoutParams();
            int width = 0;
            if (checkActualViewSize && params != null && params.width != ViewGroup.LayoutParams.WRAP_CONTENT) {
                width = view.getWidth(); // Get actual image width
            }
            if (width <= 0 && params != null) width = params.width; // Get layout width parameter
            return width;
        }
        return 0;
    }
    /**
     * 拿到高度
     * @return
     */
    @Override
    public int getHeight() {
        View view = viewRef.get();
        if (view != null) {
            final ViewGroup.LayoutParams params = view.getLayoutParams();
            int height = 0;
            if (checkActualViewSize && params != null && params.height != ViewGroup.LayoutParams.WRAP_CONTENT) {
                height = view.getHeight(); // Get actual image height
            }
            if (height <= 0 && params != null)
                height = params.height; // Get layout height parameter
            return height;
        }
        return 0;
    }
       //拿到缩放类型
    @Override
    public ViewScaleType getScaleType() {
        return ViewScaleType.CROP;
    }
 //拿到传入的View
    @Override
    public View getWrappedView() {
        return viewRef.get();
    }
//是否被回收
    @Override
    public boolean isCollected() {
        return viewRef.get() == null;
    }
 //拿到view的hashcode
    @Override
    public int getId() {
        View view = viewRef.get();
        return view == null ? super.hashCode() : view.hashCode();
    }
     //设置drawable
    @Override
    public boolean setImageDrawable(Drawable drawable) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            View view = viewRef.get();
            if (view != null) {
                setImageDrawableInto(drawable, view);
                return true;
            }
        } else {
        }
        return false;
    }
     //设置一个bitmap
    @Override
    public boolean setImageBitmap(Bitmap bitmap) {
        if (Looper.myLooper() == Looper.getMainLooper()) {
            View view = viewRef.get();
            if (view != null) {
                setImageBitmapInto(bitmap, view);
                return true;
            }
        } else {
        }
        return false;
    }
    /**
     *抽象类在子类中设置图片
     */
    protected abstract void setImageDrawableInto(Drawable drawable, View view);
    /**
     *设置Bitmap
     */
    protected abstract void setImageBitmapInto(Bitmap bitmap, View view);
}

接下来我们看一一下这个抽象类的实现,其实就是实现父类的抽象方法,实现图片的设置

* *  ImageViewAware主要是做什么的呢?
 * 该类主要是将ImageView进行一个包装,
 * 将ImageView的强引用变成弱引用,当内存不足的时候,
 * 可以更好的回收ImageView对象,还有就是获取ImageView的宽度和高度。
 * 这使得我们可以根据ImageView的宽高去对图片进行一个裁剪,减少内存的使用。
 */
public class ImageViewAware extends ViewAware {

    public ImageViewAware(ImageView imageView) {
        super(imageView);
    }


    public ImageViewAware(ImageView imageView, boolean checkActualViewSize) {
        super(imageView, checkActualViewSize);
    }

    /**
     * {@inheritDoc}
     * <br />
     * 3) Get <b>maxWidth</b>.
     */
    @Override
    public int getWidth() {
        int width = super.getWidth();
        if (width <= 0) {
            ImageView imageView = (ImageView) viewRef.get();
            if (imageView != null) {
                width = getImageViewFieldValue(imageView, "mMaxWidth"); // Check maxWidth parameter
            }
        }
        return width;
    }

    /**
     * {@inheritDoc}
     * <br />
     * 3) Get <b>maxHeight</b>
     */
    @Override
    public int getHeight() {
        int height = super.getHeight();
        if (height <= 0) {
            ImageView imageView = (ImageView) viewRef.get();
            if (imageView != null) {
                height = getImageViewFieldValue(imageView, "mMaxHeight"); // Check maxHeight parameter
            }
        }
        return height;
    }

    @Override
    public ViewScaleType getScaleType() {
        ImageView imageView = (ImageView) viewRef.get();
        if (imageView != null) {
            return ViewScaleType.fromImageView(imageView);
        }
        return super.getScaleType();
    }

    @Override
    public ImageView getWrappedView() {
        return (ImageView) super.getWrappedView();
    }

    @Override
    protected void setImageDrawableInto(Drawable drawable, View view) {
        ((ImageView) view).setImageDrawable(drawable);
        if (drawable instanceof AnimationDrawable) {
            ((AnimationDrawable) drawable).start();
        }
    }

    @Override
    protected void setImageBitmapInto(Bitmap bitmap, View view) {
        ((ImageView) view).setImageBitmap(bitmap);
    }

    private static int getImageViewFieldValue(Object object, String fieldName) {
        int value = 0;
        try {
            Field field = ImageView.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            int fieldValue = (Integer) field.get(object);
            if (fieldValue > 0 && fieldValue < Integer.MAX_VALUE) {
                value = fieldValue;
            }
        } catch (Exception e) {
            L.e(e);
        }
        return value;
    }
}

(3)接下来我们看Download包,这个包下面只有两个类,一个是ImageDownloader接口,定义了一些方法,还有根据uri拿到流,还定义了一些网络请求的参数。

public interface ImageDownloader {
    /**
    根据uri 拿到流
     */
    InputStream getStream(String imageUri, Object extra) throws IOException;
    /** Represents supported schemes(protocols) of URI. Provides convenient methods for work with schemes and URIs.
     * 支持的网络请求协议类型
     * */
    public enum Scheme {
        HTTP("http"), HTTPS("https"), FILE("file"), CONTENT("content"), ASSETS("assets"), DRAWABLE("drawable"), UNKNOWN("");
        private String scheme;
        private String uriPrefix;
        Scheme(String scheme) {
            this.scheme = scheme;
            uriPrefix = scheme + "://";
        }
        /**判断类型
         */
        public static Scheme ofUri(String uri) {
            if (uri != null) {
                for (Scheme s : values()) {
                    if (s.belongsTo(uri)) {
                        return s;
                    }
                }
            }
            return UNKNOWN;
        }
          //
        private boolean belongsTo(String uri) {
            return uri.toLowerCase(Locale.US).startsWith(uriPrefix);
        }
        /** Appends scheme to incoming path //获取全路径  */
        public String wrap(String path) {
            return uriPrefix + path;
        }

        /** 获取剔除前缀的路径 */
        public String crop(String uri) {
            if (!belongsTo(uri)) {
                throw new IllegalArgumentException(String.format("URI [%1$s] doesn't have expected scheme [%2$s]", uri, scheme));
            }
            return uri.substring(uriPrefix.length());
        }
    }
}

(4)我们再来看一下display这个包,这个包里面是一个接口BitmapDisplayer,和他们的实现类,包括环形展示器,渐入渐出展示器,圆角展示器,还有一个简单的展示器,因为这个不是重点,所以我们看一下接口和实现就可以了。

public interface BitmapDisplayer {
    /**一个接口 要一个bitmap  要一个
     */
    void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom);
}
public final class SimpleBitmapDisplayer implements BitmapDisplayer {
    @Override
    public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
        imageAware.setImageBitmap(bitmap);
    }
}

(5)我们看下面一个包deocde,这个是一个编译包,将图片转化为Bitmap,这个包下面包含一个接口ImageDecoder,BaseImageDecoder实现类,ImageDecodingInfo实体类

接口非常简单

public interface ImageDecoder {
    /***
     *
     * @param imageDecodingInfo
     * @return
     * @throws IOException
     */
    Bitmap decode(ImageDecodingInfo imageDecodingInfo) throws IOException;
}

包含图片编码转化的信息

public class ImageDecodingInfo {

    private final String imageKey;
    private final String imageUri;
    private final String originalImageUri;
    private final ImageSize targetSize;

    private final ImageScaleType imageScaleType;//缩放类型
    private final ViewScaleType viewScaleType;

    private final ImageDownloader downloader;//图片下载器
    private final Object extraForDownloader;//

    private final boolean considerExifParams;
    private final Options decodingOptions;

    public ImageDecodingInfo(String imageKey, String imageUri, String originalImageUri, ImageSize targetSize, ViewScaleType viewScaleType,
                             ImageDownloader downloader, DisplayImageOptions displayOptions) {
        this.imageKey = imageKey;
        this.imageUri = imageUri;
        this.originalImageUri = originalImageUri;
        this.targetSize = targetSize;

        this.imageScaleType = displayOptions.getImageScaleType();
        this.viewScaleType = viewScaleType;

        this.downloader = downloader;
        this.extraForDownloader = displayOptions.getExtraForDownloader();

        considerExifParams = displayOptions.isConsiderExifParams();
        decodingOptions = new Options();
        copyOptions(displayOptions.getDecodingOptions(), decodingOptions);
    }

    private void copyOptions(Options srcOptions, Options destOptions) {
        destOptions.inDensity = srcOptions.inDensity;
        destOptions.inDither = srcOptions.inDither;
        destOptions.inInputShareable = srcOptions.inInputShareable;
        destOptions.inJustDecodeBounds = srcOptions.inJustDecodeBounds;
        destOptions.inPreferredConfig = srcOptions.inPreferredConfig;
        destOptions.inPurgeable = srcOptions.inPurgeable;
        destOptions.inSampleSize = srcOptions.inSampleSize;
        destOptions.inScaled = srcOptions.inScaled;
        destOptions.inScreenDensity = srcOptions.inScreenDensity;
        destOptions.inTargetDensity = srcOptions.inTargetDensity;
        destOptions.inTempStorage = srcOptions.inTempStorage;
        if (Build.VERSION.SDK_INT >= 10) copyOptions10(srcOptions, destOptions);
        if (Build.VERSION.SDK_INT >= 11) copyOptions11(srcOptions, destOptions);
    }

    @TargetApi(10)
    private void copyOptions10(Options srcOptions, Options destOptions) {
        destOptions.inPreferQualityOverSpeed = srcOptions.inPreferQualityOverSpeed;
    }

    @TargetApi(11)
    private void copyOptions11(Options srcOptions, Options destOptions) {
        destOptions.inBitmap = srcOptions.inBitmap;
        destOptions.inMutable = srcOptions.inMutable;
    }

    public String getImageKey() {
        return imageKey;
    }

    /** @return Image URI for decoding (usually image from disk cache) */
    public String getImageUri() {
        return imageUri;
    }

    /** @return The original image URI which was passed to ImageLoader */
    public String getOriginalImageUri() {
        return originalImageUri;
    }

    /**
     * @return Target size for image. Decoded bitmap should close to this size according to {@linkplain ImageScaleType
     * image scale type} and {@linkplain ViewScaleType view scale type}.
     */
    public ImageSize getTargetSize() {
        return targetSize;
    }

    /**
     * @return {@linkplain ImageScaleType Scale type for image sampling and scaling}. This parameter affects result size
     * of decoded bitmap.
     */
    public ImageScaleType getImageScaleType() {
        return imageScaleType;
    }

    /** @return {@linkplain ViewScaleType View scale type}. This parameter affects result size of decoded bitmap. */
    public ViewScaleType getViewScaleType() {
        return viewScaleType;
    }

    /** @return Downloader for image loading */
    public ImageDownloader getDownloader() {
        return downloader;
    }

    /** @return Auxiliary object for downloader */
    public Object getExtraForDownloader() {
        return extraForDownloader;
    }

    /** @return <b>true</b> - if EXIF params of image should be considered; <b>false</b> - otherwise */
    public boolean shouldConsiderExifParams() {
        return considerExifParams;
    }

    /** @return Decoding options */
    public Options getDecodingOptions() {
        return decodingOptions;
    }
}

(6)最后我们来看一下assist这个包,里面包含了一个deque的包还有其他类型,这些类型主要包括一些缩放的类型定义,处理队列定义,从何处加载定义,图片大小实体类定义,图片缩放类型定义,流刷定义,错误实体类定义,内容输入流长度定义。由于都比较简单易懂,我直接把代码放上来。

//图片缩放的类型
public enum ViewScaleType {
    FIT_INSIDE,
    CROP;
       //判断类型
    public static ViewScaleType fromImageView(ImageView imageView) {
        switch (imageView.getScaleType()) {
            case FIT_CENTER:
            case FIT_XY:
            case FIT_START:
            case FIT_END:
            case CENTER_INSIDE:
                return FIT_INSIDE;
            case MATRIX:
            case CENTER:
            case CENTER_CROP:
            default:
                return CROP;
        }
    }
}
/**
 * Queue processing type which will be used for display task processing
 * 请求队列的处理类型
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
 * @since 1.6.3
 */
public enum QueueProcessingType {
    FIFO, LIFO
}
/**
 * Source image loaded from.
 *一个枚举 里面是图片获取的状态
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
 */
public enum LoadedFrom {
    NETWORK, DISC_CACHE, MEMORY_CACHE
}
/**
 * Present width and height values
 *图片大小的实体类
 * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
 * @since 1.0.0
 */
public class ImageSize {
    private static final int TO_STRING_MAX_LENGHT = 9; // "9999x9999".length()
    private static final String SEPARATOR = "x";
    private final int width;
    private final int height;
    public ImageSize(int width, int height) {
        this.width = width;
        this.height = height;
    }
    public ImageSize(int width, int height, int rotation) {
        if (rotation % 180 == 0) {
            this.width = width;
            this.height = height;
        } else {
            this.width = height;
            this.height = width;
        }
    }
    public int getWidth() {
        return width;
    }
    public int getHeight() {
        return height;
    }
    /** Scales down dimensions in <b>sampleSize</b> times. Returns new object. */
    public ImageSize scaleDown(int sampleSize) {
        return new ImageSize(width / sampleSize, height / sampleSize);
    }
    /** Scales dimensions according to incoming scale. Returns new object. */
    public ImageSize scale(float scale) {
        return new ImageSize((int) (width * scale), (int) (height * scale));
    }
    @Override
    public String toString() {
        return new StringBuilder(TO_STRING_MAX_LENGHT).append(width).append(SEPARATOR).append(height).toString();
    }
}
/**
 *图片缩放的类型
 */
public enum ImageScaleType {
    /** Image won't be scaled */
    NONE,
    /**
     */
    NONE_SAFE,
    /**
     */
    IN_SAMPLE_POWER_OF_2,
    /**
     */
    IN_SAMPLE_INT,
    /**
     */
    EXACTLY,
    /**
     */
    EXACTLY_STRETCHED
}
/**但是BitmapFactory类的decodeStream方法在网络超时或较慢的时候无法获取完整的数据.这是因为google对于InputStream流有个小bug,
 在慢速网络的情况下可能产生中断。我们可以考虑重写FilterInputStream处理skip方法来解决这个bug。
 这里我们通过继承FilterInputStream类的skip方法来强制实现flush流中的数据,
 主要原理就是检查是否到文件末端,告诉http类是否继续。
 */
public class FlushedInputStream extends FilterInputStream {
    public FlushedInputStream(InputStream inputStream) {
        super(inputStream);
    }
    @Override
    public long skip(long n) throws IOException {
        long totalBytesSkipped = 0L;
        while (totalBytesSkipped < n) {
            long bytesSkipped = in.skip(n - totalBytesSkipped);
            if (bytesSkipped == 0L) {
                int by_te = read();
                if (by_te < 0) {
                    break; // we reached EOF
                } else {
                    bytesSkipped = 1; // we read one byte
                }
            }
            totalBytesSkipped += bytesSkipped;
        }
        return totalBytesSkipped;
    }
}
/**
 *请求失败的实体类
 */
public class FailReason {
    private final FailType type; //失败的类型
    private final Throwable cause;//错误
    public FailReason(FailType type, Throwable cause) {
        this.type = type;
        this.cause = cause;
    }
    public FailType getType() {
        return type;
    }
    public Throwable getCause() {
        return cause;
    }
    public static enum FailType {
        /** Input/output error. Can be caused by network communication fail or error while caching image on file system. */
        IO_ERROR,
        /**
         * Error while
         * decode image to Bitmap}
         */
        DECODING_ERROR,
        /**
         * downloads are denied} and requested image wasn't cached in disk cache before.
         */
        NETWORK_DENIED,
        /** Not enough memory to create needed Bitmap for image */
        OUT_OF_MEMORY,
        /** Unknown error was occurred while loading image */
        UNKNOWN
    }
}

public class ContentLengthInputStream extends InputStream {
    private final InputStream stream;
    private final int length;
    public ContentLengthInputStream(InputStream stream, int length) {
        this.stream = stream;
        this.length = length;
    }
    @Override
    public int available() {
        return length;
    }
    @Override
    public void close() throws IOException {
        stream.close();
    }
    @Override
    public void mark(int readLimit) {
        stream.mark(readLimit);
    }
    @Override
    public int read() throws IOException {
        return stream.read();
    }
    @Override
    public int read(byte[] buffer) throws IOException {
        return stream.read(buffer);
    }
    @Override
    public int read(byte[] buffer, int byteOffset, int byteCount) throws IOException {
        return stream.read(buffer, byteOffset, byteCount);
    }
    @Override
    public void reset() throws IOException {
        stream.reset();
    }
    @Override
    public long skip(long byteCount) throws IOException {
        return stream.skip(byteCount);
    }
    @Override
    public boolean markSupported() {
        return stream.markSupported();
    }
}

四、结合归纳。

上一篇和这一篇,基本上把ImageLoader的所有类都看完了,接下来我们做一个简单的总结,其实我们打开Universal-ImageLoader这个项目,分为三个部分,第一部分是内存缓存磁盘缓存部分,第二部分是核心部分,第三部分是工具类(不是重点),首先从根据Uri生成key 将它与控件ImageAware对应,从内存中获取指定的keyBitmap,如果内存没有Bitmap就启动LoadAndDisplayImageTask,它会先去内存找,内存没有就去磁盘找,磁盘没就去网络下载,然后刷新内存和磁盘缓存,然后启动DisplayBitmapTask去展示,如果内存有那直接开启ProcessAndDisplayImageTask去处理图片,然后调用DisplayBitmapTask去展示关于内存方面,源码是如果你没有特殊设置,内存缓存是使用LruMemoryCache,大小是如果你没有传,那么就使用app最大内存的八分之一,如果有传那么就以你设置的最大内存,磁盘缓存是如果你没有传大小,那么就用无限制的磁盘缓存,如果有传,那么就以你传的大小的LruDiskCache 作为内存限制。所以这就是Universal-Image-Loader的整体执行流程。

猜你喜欢

转载自blog.csdn.net/a820703048/article/details/79201111