ImageLoader使用及源码解析

智能手机的普遍使用,使人们不再满足于文字以及少量图标显示。考虑到之前手机内存的限制与app安装包的体量大小,选择使用加载网络图片到app是一个很好的选择,但是大量的加载图片又会引发其他问题,比如:让用户产生过多流量费用、图片加载速度的提升等,这就要求对图片进行缓存;内存溢出(Out Of Memery,简称OOM),这就要求对加载的图片进行处理。有好多第三方开源框架做的比较成熟,比如ImageLoader、Picasso、Fresco、Glide等,道长今天说说ImageLoader。

一、ImageLoader的优点

  • 支持下载进度监听

  • 可以在View滚动中暂停图片加载
    通过 PauseOnScrollListener 接口可以在 View 滚动中暂停图片加载。

  • 默认实现多种内存缓存算法
    ImageLoader 默认实现了较多缓存算法,如 Size 最大先删除、使用最少先删除、最近最少使用、先进先删除、时间最长先删除等。

  • 支持本地缓存文件名规则定义

二、ImageLoader的使用

  • ImageLoader下载
    道长的项目中使用的是1.9.1版本的,最新的是1.9.5版本的,如果有需要,点击传送门在gitHub自行下载:ImageLoader.jar下载

1.初始化ImageLoader

    private static void initImageLoader(Context context) {
        File cacheDir = StorageUtils.getOwnCacheDirectory(context,
                "yushan/iamgeloader");
        DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
                .cacheInMemory(true).cacheOnDisc(true)
                .bitmapConfig(Config.RGB_565)// 设置图片解码类型
                .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
                .considerExifParams(false)// 不考虑iamge的翻转
                .build();

        // 基本配置
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(
                context)
                .denyCacheImageMultipleSizesInMemory()                 // 一个URL只缓存一张图片
                .discCacheFileNameGenerator(new Md5FileNameGenerator())// 文件名MD5加密
                .defaultDisplayImageOptions(defaultOptions)
                .discCache(new UnlimitedDiscCache(cacheDir))           // 自定义缓存路径
                .discCacheSize(50 * 1024 * 1024)                       // 磁盘缓存大小
                .discCacheFileCount(100)                               // 缓存100图片
                .memoryCache(new WeakMemoryCache())
                .memoryCache(new LruMemoryCache(2 * 1024 * 1024))
                .memoryCacheSize(2 * 1024 * 1024).memoryCacheSizePercentage(13) // default
                .threadPoolSize(2).writeDebugLogs().build();
        ImageLoader.getInstance().init(config);
    }

2.获取ImageLoader实例

    /**
     * 获取图片异步加载ImageLoader对象
     *
     * @return
     */
    public static ImageLoader getImageLoaderIntance() {
        if (iamgeLoader == null) {
            iamgeLoader = ImageLoader.getInstance();
        }
        return iamgeLoader;
    }

3.初始化下载器

在初始化下载器时可以根据自己的需求设置缓存位置以及其他设置。

options = new DisplayImageOptions.Builder().cacheInMemory(false)
            .cacheOnDisc(true)
            // 注意:compete_loading_default 在下次迭代中删除
            .showStubImage(R.drawable.club_more_activity_head)
            // 设置图片下载期间显示的图片
            .showImageForEmptyUri(R.drawable.club_more_activity_head)
            // 设置图片uri为空时显示的图片
            .showImageOnFail(R.drawable.club_more_activity_head)
            // 设置图片加载或解码转换失败时显示的图片
            .considerExifParams(true)
            .bitmapConfig(Bitmap.Config.RGB_565)
            .imageScaleType(ImageScaleType.EXACTLY).build();

4.下载并装载图片

try {
        iv_coin.setVisibility(View.VISIBLE);
        imageLoader.displayImage(logo, iv_coin, options);
    } catch (Exception e) {
        e.printStackTrace();
    }

ImageLoader的使用不是道长说的重点,这里也就简单说一下ImageLoader的使用。

三、ImageLoader的源码解析

1.获取ImageLoader实例

我们可以看到ImageLoader的实例获取是单例模式,并且添加了通信安全机制防止图片加载成功之前再次创建实例。

    public static ImageLoader getInstance() {
        if(instance == null) {
            Class var0 = ImageLoader.class;
            synchronized(ImageLoader.class) {
                if(instance == null) {
                    instance = new ImageLoader();
                }
            }
        }

        return instance;
    }

2.下载器的构造器

构造器没有什么可以说的,就是一些参数设置。

        public Builder() {
            this.imageScaleType = ImageScaleType.IN_SAMPLE_POWER_OF_2;
            this.decodingOptions = new Options();
            this.delayBeforeLoading = 0;
            this.considerExifParams = false;
            this.extraForDownloader = null;
            this.preProcessor = null;
            this.postProcessor = null;
            this.displayer = DefaultConfigurationFactory.createBitmapDisplayer();
            this.handler = null;
            this.isSyncLoading = false;
            this.decodingOptions.inPurgeable = true;
            this.decodingOptions.inInputShareable = true;
        }

3.下载并装载图片

  • 通过道长调用的方法看到源码方法实现
    public void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {
        this.displayImage(uri, (ImageAware)(new ImageViewAware(imageView)), options, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
    }
  • 还有displayImage的重载方法
    public void displayImage(String uri, ImageAware imageAware) {
        this.displayImage(uri, (ImageAware)imageAware, (DisplayImageOptions)null, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
    }

    public void displayImage(String uri, ImageAware imageAware, ImageLoadingListener listener) {
        this.displayImage(uri, (ImageAware)imageAware, (DisplayImageOptions)null, listener, (ImageLoadingProgressListener)null);
    }

    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options) {
        this.displayImage(uri, (ImageAware)imageAware, options, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
    }

    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener) {
        this.displayImage(uri, (ImageAware)imageAware, options, listener, (ImageLoadingProgressListener)null);
    }

    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        this.checkConfiguration();
        if(imageAware == null) {
            throw new IllegalArgumentException("Wrong arguments were passed to displayImage() method (ImageView reference must not be null)");
        } else {
            if(listener == null) {
                listener = this.emptyListener;
            }

            if(options == null) {
                options = this.configuration.defaultDisplayImageOptions;
            }

            if(TextUtils.isEmpty(uri)) {
                this.engine.cancelDisplayTaskFor(imageAware);
                listener.onLoadingStarted(uri, imageAware.getWrappedView());
                if(options.shouldShowImageForEmptyUri()) {
                    imageAware.setImageDrawable(options.getImageForEmptyUri(this.configuration.resources));
                } else {
                    imageAware.setImageDrawable((Drawable)null);
                }

                listener.onLoadingComplete(uri, imageAware.getWrappedView(), (Bitmap)null);
            } else {
                ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, this.configuration.getMaxImageSize());
                String memoryCacheKey = MemoryCacheUtil.generateKey(uri, targetSize);
                this.engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);
                listener.onLoadingStarted(uri, imageAware.getWrappedView());
                Bitmap bmp = (Bitmap)this.configuration.memoryCache.get(memoryCacheKey);
                ImageLoadingInfo imageLoadingInfo;
                if(bmp != null && !bmp.isRecycled()) {
                    if(this.configuration.writeLogs) {
                        L.d("Load image from memory cache [%s]", new Object[]{memoryCacheKey});
                    }

                    if(options.shouldPostProcess()) {
                        imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri));
                        ProcessAndDisplayImageTask displayTask1 = new ProcessAndDisplayImageTask(this.engine, bmp, imageLoadingInfo, options.getHandler());
                        if(options.isSyncLoading()) {
                            displayTask1.run();
                        } else {
                            this.engine.submit(displayTask1);
                        }
                    } else {
                        options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
                        listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
                    }
                } else {
                    if(options.shouldShowImageOnLoading()) {
                        imageAware.setImageDrawable(options.getImageOnLoading(this.configuration.resources));
                    } else if(options.isResetViewBeforeLoading()) {
                        imageAware.setImageDrawable((Drawable)null);
                    }

                    imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri));
                    LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(this.engine, imageLoadingInfo, options.getHandler());
                    if(options.isSyncLoading()) {
                        displayTask.run();
                    } else {
                        this.engine.submit(displayTask);
                    }
                }

            }
        }
    }

    public void displayImage(String uri, ImageView imageView) {
        this.displayImage(uri, (ImageAware)(new ImageViewAware(imageView)), (DisplayImageOptions)null, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
    }

    public void displayImage(String uri, ImageView imageView, DisplayImageOptions options) {
        this.displayImage(uri, (ImageAware)(new ImageViewAware(imageView)), options, (ImageLoadingListener)null, (ImageLoadingProgressListener)null);
    }

    public void displayImage(String uri, ImageView imageView, ImageLoadingListener listener) {
        this.displayImage(uri, (ImageAware)(new ImageViewAware(imageView)), (DisplayImageOptions)null, listener, (ImageLoadingProgressListener)null);
    }

    public void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener) {
        this.displayImage(uri, (ImageView)imageView, options, listener, (ImageLoadingProgressListener)null);
    }

    public void displayImage(String uri, ImageView imageView, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        this.displayImage(uri, (ImageAware)(new ImageViewAware(imageView)), options, listener, progressListener);
    }

ImageLoader作为一个成熟的图片加在框架不可能只有这么一种加载方式。

  • 加载方式二
  public void loadImage(String uri, ImageLoadingListener listener) {
        this.loadImage(uri, (ImageSize)null, (DisplayImageOptions)null, listener, (ImageLoadingProgressListener)null);
    }

    public void loadImage(String uri, ImageSize targetImageSize, ImageLoadingListener listener) {
        this.loadImage(uri, targetImageSize, (DisplayImageOptions)null, listener, (ImageLoadingProgressListener)null);
    }

    public void loadImage(String uri, DisplayImageOptions options, ImageLoadingListener listener) {
        this.loadImage(uri, (ImageSize)null, options, listener, (ImageLoadingProgressListener)null);
    }

    public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options, ImageLoadingListener listener) {
        this.loadImage(uri, targetImageSize, options, listener, (ImageLoadingProgressListener)null);
    }

    public void loadImage(String uri, ImageSize targetImageSize, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        this.checkConfiguration();
        if(targetImageSize == null) {
            targetImageSize = this.configuration.getMaxImageSize();
        }

        if(options == null) {
            options = this.configuration.defaultDisplayImageOptions;
        }

        ImageNonViewAware imageAware = new ImageNonViewAware(uri, targetImageSize, ViewScaleType.CROP);
        this.displayImage(uri, (ImageAware)imageAware, options, listener, progressListener);
    }
  • 加载方式三
public Bitmap loadImageSync(String uri) {
        return this.loadImageSync(uri, (ImageSize)null, (DisplayImageOptions)null);
    }

    public Bitmap loadImageSync(String uri, DisplayImageOptions options) {
        return this.loadImageSync(uri, (ImageSize)null, options);
    }

    public Bitmap loadImageSync(String uri, ImageSize targetImageSize) {
        return this.loadImageSync(uri, targetImageSize, (DisplayImageOptions)null);
    }

    public Bitmap loadImageSync(String uri, ImageSize targetImageSize, DisplayImageOptions options) {
        if(options == null) {
            options = this.configuration.defaultDisplayImageOptions;
        }

        options = (new Builder()).cloneFrom(options).syncLoading(true).build();
        SyncImageLoadingListener listener = new SyncImageLoadingListener();
        this.loadImage(uri, targetImageSize, options, listener);
        return listener.getLoadedBitmap();
    }

4.分析装载图片方法

大家可以看到加载方式三(loadImageSync)有这样一行代码:

        this.loadImage(uri, targetImageSize, options, listener);

这一行代码调用了加载方式二(loadImage),也就是说加载方式三(loadImageSync)是通过调用加载方式二(loadImage)实现的。而我们再看加载方式二(loadImage)的实现方式。在加载方式二(loadImage)中发现这么一行代码:

this.displayImage(uri, (ImageAware)imageAware, options, listener, progressListener);

到这里我们就知道了ImageLoader加载图片最终实现方式都是通过调用displayImage()这个方法实现的。

咱们回头看一下displayImage()这个方法的实现:

  • displayImage()传参
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener){}

uri - 加载图片的路径
imageAware - 图片的装载容器
optins - 图片的加载器
listener - 图片的加载监听方法
progressListener - 图片的加载进度监听方法

加载图片的路径(uri)咱们就不多说了,咱们先看一下图片的装载容器(imageAware):

public interface ImageAware {
    int getWidth();

    int getHeight();

    ViewScaleType getScaleType();

    View getWrappedView();

    boolean isCollected();

    int getId();

    boolean setImageDrawable(Drawable var1);

    boolean setImageBitmap(Bitmap var1);
}

我们看到ImageAware是一个接口,接口中含有一些属性和方法,有两个类(ImageViewAware、ImageNonViewAware)实现了ImageAware接口。这里我们就不贴这两个类的代码了。

图片加载器(optins)咱们也不说了,就是一些参数的设置和初始化。图片的加载监听方法(listener)的代码如下:

public interface ImageLoadingListener {
    void onLoadingStarted(String var1, View var2);

    void onLoadingFailed(String var1, View var2, FailReason var3);

    void onLoadingComplete(String var1, View var2, Bitmap var3);

    void onLoadingCancelled(String var1, View var2);
}

我们看到这个接口有四个方法,代表加载图片的四种状态:started、failed、complete、cancelled。

图片的加载进度监听方法(progressListener)的代码如下:

public interface ImageLoadingProgressListener {
    void onProgressUpdate(String var1, View var2, int var3, int var4);
}

其实么有什么好说的,就是返回加载进度。

  • displayImage()参数判断
    public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageLoadingListener listener, ImageLoadingProgressListener progressListener) {
        this.checkConfiguration();
        if(imageAware == null) {
            throw new IllegalArgumentException("Wrong arguments were passed to displayImage() method (ImageView reference must not be null)");
        } else {
            if(listener == null) {
                listener = this.emptyListener;
            }

            if(options == null) {
                options = this.configuration.defaultDisplayImageOptions;
            }
            ……
        }
    }

我们可以看到当imageAware为null时直接抛异常,而listener和options为null时直接调用默认设置。然后咱们接着往下看,先看一下uri为null时的一些处理:

if(TextUtils.isEmpty(uri)) {
    this.engine.cancelDisplayTaskFor(imageAware);
    listener.onLoadingStarted(uri, imageAware.getWrappedView());
    if(options.shouldShowImageForEmptyUri()) {
        imageAware.setImageDrawable(options.getImageForEmptyUri(this.configuration.resources));
    } else {
        imageAware.setImageDrawable((Drawable)null);
    }

    listener.onLoadingComplete(uri, imageAware.getWrappedView(), (Bitmap)null);
} else {
……
}

当uri为null时,先调用了cancelDisplayTaskFor()取消下载图片任务,源码如下:

    void cancelDisplayTaskFor(ImageAware imageAware) {
        this.cacheKeysForImageAwares.remove(Integer.valueOf(imageAware.getId()));
    }

这里出现了engine,engine是ImageLoader的核心,关于engine咱么等一下再说。
然后调用了listener.onLoadingStarted()用来实现监听,然后判断在uri为null时是否显示默认图片。然后调用listener.onLoadingComplete()用来实现监听。
然后咱们再看一下uri不为null时的源码:

ImageSize targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, this.configuration.getMaxImageSize());
                String memoryCacheKey = MemoryCacheUtil.generateKey(uri, targetSize);
                this.engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);
                listener.onLoadingStarted(uri, imageAware.getWrappedView());
                Bitmap bmp = (Bitmap)this.configuration.memoryCache.get(memoryCacheKey);
                ImageLoadingInfo imageLoadingInfo;
                if(bmp != null && !bmp.isRecycled()) {
                    if(this.configuration.writeLogs) {
                        L.d("Load image from memory cache [%s]", new Object[]{memoryCacheKey});
                    }

                    if(options.shouldPostProcess()) {
                        imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri));
                        ProcessAndDisplayImageTask displayTask1 = new ProcessAndDisplayImageTask(this.engine, bmp, imageLoadingInfo, options.getHandler());
                        if(options.isSyncLoading()) {
                            displayTask1.run();
                        } else {
                            this.engine.submit(displayTask1);
                        }
                    } else {
                        options.getDisplayer().display(bmp, imageAware, LoadedFrom.MEMORY_CACHE);
                        listener.onLoadingComplete(uri, imageAware.getWrappedView(), bmp);
                    }
                } else {
                    if(options.shouldShowImageOnLoading()) {
                        imageAware.setImageDrawable(options.getImageOnLoading(this.configuration.resources));
                    } else if(options.isResetViewBeforeLoading()) {
                        imageAware.setImageDrawable((Drawable)null);
                    }

                    imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri));
                    LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(this.engine, imageLoadingInfo, options.getHandler());
                    if(options.isSyncLoading()) {
                        displayTask.run();
                    } else {
                        this.engine.submit(displayTask);
                    }
                }

第一行代码就是测量控件的宽高并以实体的形式返回。
第二行代码就是拼接缓存路径。
第三行代码就是添加下载任务。
第四行代码就是调用接口,告诉加载状态变为started。
第五行代码就是获取缓存中的图片。
……

  • displayImage()的缓存

这里咱们要说一下ImageLoader的缓存,顶级接口如下:

public interface MemoryCacheAware {
    boolean put(K var1, V var2);

    V get(K var1);

    void remove(K var1);

    Collection keys();

    void clear();
}

咱们从实现这个接口的方面看一下:
ImageLoader使用及源码解析_第1张图片

FuzzyKeyMemoryCache - 按照类的注释,这个类是框架内部使用的
LimitedAgeMemoryCache - 当 bitmap加入缓存中的时间超过我们设定的值,将其删除
LruMemoryCache - 这个类就是这个开源框架默认的内存缓存类,缓存的是bitmap的强引用

也就是说有四种缓存方式,当然baseMemoryCache还有一些子类对baseMemoryCache的功能进行了扩展。咱们这里就不介绍这么详细了,如果有时间在详细说一下。

然后咱们接着往下看,这里有一个判断,当bmp != null 并且 !bmp.isRecycled()时,就会有一种操作:重新下载还是加载缓存;反之,就直接下载图片。当然这里还会有一些其他操作,比如,加载方式是不是异步,加载中是不是展示默认图片等等。

  • displayImage()下载图片
                    imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri));
                    LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(this.engine, imageLoadingInfo, options.getHandler());
                    if(options.isSyncLoading()) {
                        displayTask.run();
                    } else {
                        this.engine.submit(displayTask);
                    }

咱们看到加载图片有两种方式,异步加载和同步加载。咱们先看一下异步加载,异步加载调用的代码displayTask.run()。源码如下:

    public void run() {
        if(!this.waitIfPaused()) {
            if(!this.delayIfNeed()) {
                ReentrantLock loadFromUriLock = this.imageLoadingInfo.loadFromUriLock;
                this.log("Start display image task [%s]");
                if(loadFromUriLock.isLocked()) {
                    this.log("Image already is loading. Waiting... [%s]");
                }

                loadFromUriLock.lock();

                Bitmap bmp;
                label132: {
                    try {
                        this.checkTaskNotActual();
                        bmp = (Bitmap)this.configuration.memoryCache.get(this.memoryCacheKey);
                        if(bmp == null) {
                            bmp = this.tryLoadBitmap();
                            if(bmp == null) {
                                return;
                            }

                            this.checkTaskNotActual();
                            this.checkTaskInterrupted();
                            if(this.options.shouldPreProcess()) {
                                this.log("PreProcess image before caching in memory [%s]");
                                bmp = this.options.getPreProcessor().process(bmp);
                                if(bmp == null) {
                                    L.e("Pre-processor returned null [%s]", new Object[]{this.memoryCacheKey});
                                }
                            }

                            if(bmp != null && this.options.isCacheInMemory()) {
                                this.log("Cache image in memory [%s]");
                                this.configuration.memoryCache.put(this.memoryCacheKey, bmp);
                            }
                        } else {
                            this.loadedFrom = LoadedFrom.MEMORY_CACHE;
                            this.log("...Get cached bitmap from memory after waiting. [%s]");
                        }

                        if(bmp != null && this.options.shouldPostProcess()) {
                            this.log("PostProcess image before displaying [%s]");
                            bmp = this.options.getPostProcessor().process(bmp);
                            if(bmp == null) {
                                L.e("Post-processor returned null [%s]", new Object[]{this.memoryCacheKey});
                            }
                        }

                        this.checkTaskNotActual();
                        this.checkTaskInterrupted();
                        break label132;
                    } catch (LoadAndDisplayImageTask.TaskCancelledException var7) {
                        this.fireCancelEvent();
                    } finally {
                        loadFromUriLock.unlock();
                    }

                    return;
                }

                DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(bmp, this.imageLoadingInfo, this.engine, this.loadedFrom);
                displayBitmapTask.setLoggingEnabled(this.writeLogs);
                if(this.options.isSyncLoading()) {
                    displayBitmapTask.run();
                } else {
                    this.handler.post(displayBitmapTask);
                }

            }
        }
    }

其中代码bmp = this.tryLoadBitmap();为加载图片方法,实现如下:

    private Bitmap tryLoadBitmap() throws LoadAndDisplayImageTask.TaskCancelledException {
        File imageFile = this.getImageFileInDiscCache();
        Bitmap bitmap = null;

        try {
            String e = Scheme.FILE.wrap(imageFile.getAbsolutePath());
            if(imageFile.exists()) {
                this.log("Load image from disc cache [%s]");
                this.loadedFrom = LoadedFrom.DISC_CACHE;
                this.checkTaskNotActual();
                bitmap = this.decodeImage(e);
            }

            if(bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
                this.log("Load image from network [%s]");
                this.loadedFrom = LoadedFrom.NETWORK;
                String imageUriForDecoding = this.options.isCacheOnDisc() && this.tryCacheImageOnDisc(imageFile)?e:this.uri;
                this.checkTaskNotActual();
                bitmap = this.decodeImage(imageUriForDecoding);
                if(bitmap == null || bitmap.getWidth() <= 0 || bitmap.getHeight() <= 0) {
                    this.fireFailEvent(FailType.DECODING_ERROR, (Throwable)null);
                }
            }
        } catch (IllegalStateException var5) {
            this.fireFailEvent(FailType.NETWORK_DENIED, (Throwable)null);
        } catch (LoadAndDisplayImageTask.TaskCancelledException var6) {
            throw var6;
        } catch (IOException var7) {
            L.e(var7);
            this.fireFailEvent(FailType.IO_ERROR, var7);
            if(imageFile.exists()) {
                imageFile.delete();
            }
        } catch (OutOfMemoryError var8) {
            L.e(var8);
            this.fireFailEvent(FailType.OUT_OF_MEMORY, var8);
        } catch (Throwable var9) {
            L.e(var9);
            this.fireFailEvent(FailType.UNKNOWN, var9);
        }

        return bitmap;
    }

并且进行了缓存处理:

if(bmp != null && this.options.isCacheInMemory()) {
                                this.log("Cache image in memory [%s]");
                                this.configuration.memoryCache.put(this.memoryCacheKey, bmp);
                            }

然后我们最后又调用了displayBitmapTask.run()装载图片,源码如下:

    public void run() {
        if(this.imageAware.isCollected()) {
            if(this.loggingEnabled) {
                L.d("ImageAware was collected by GC. Task is cancelled. [%s]", new Object[]{this.memoryCacheKey});
            }

            this.listener.onLoadingCancelled(this.imageUri, this.imageAware.getWrappedView());
        } else if(this.isViewWasReused()) {
            if(this.loggingEnabled) {
                L.d("ImageAware is reused for another image. Task is cancelled. [%s]", new Object[]{this.memoryCacheKey});
            }

            this.listener.onLoadingCancelled(this.imageUri, this.imageAware.getWrappedView());
        } else {
            if(this.loggingEnabled) {
                L.d("Display image in ImageAware (loaded from %1$s) [%2$s]", new Object[]{this.loadedFrom, this.memoryCacheKey});
            }

            this.displayer.display(this.bitmap, this.imageAware, this.loadedFrom);
            this.listener.onLoadingComplete(this.imageUri, this.imageAware.getWrappedView(), this.bitmap);
            this.engine.cancelDisplayTaskFor(this.imageAware);
        }

    }

我们看this.displayer.display(this.bitmap, this.imageAware, this.loadedFrom);这行代码,只是把bitmap装载到imageAware上,咱们追踪一下源码:

获取displayer实例:

this.displayer = imageLoadingInfo.options.getDisplayer();

DisplayImageOptions.Builder()中的构造代码调用:

this.displayer = DefaultConfigurationFactory.createBitmapDisplayer();

调用DefaultConfigurationFactory中方法:

    public static BitmapDisplayer createBitmapDisplayer() {
        return new SimpleBitmapDisplayer();
    }

SimpleBitmapDisplayer中方法实现:

    public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
        imageAware.setImageBitmap(bitmap);
    }

异步加载图片说完了,咱们再说说同步加载图片,其实创建任务是和异步相同的,只是调用不同,源码如下:

    void submit(final LoadAndDisplayImageTask task) {
        this.taskDistributor.execute(new Runnable() {
            public void run() {
                boolean isImageCachedOnDisc = ImageLoaderEngine.this.configuration.discCache.get(task.getLoadingUri()).exists();
                ImageLoaderEngine.this.initExecutorsIfNeed();
                if(isImageCachedOnDisc) {
                    ImageLoaderEngine.this.taskExecutorForCachedImages.execute(task);
                } else {
                    ImageLoaderEngine.this.taskExecutor.execute(task);
                }

            }
        });
    }

好了,到了这里咱们算是把ImageLoader的整体流程梳理了一遍,其他的就不说了,等有时间了再说一下ImageLoader的缓存。希望这篇博客能够为你提供一些帮助。


你可能感兴趣的:(android-第三方框架,android开发利器)