Android Universal-Image-Loader 解析

任务流图

任务流图中的每一步都有自己的接口(在图片底部)来负责这部分的任务。大部分接口(除了BitmapProcessor)都拥有默认的实现从左到右依次是BaseImageDowloader、UnlimitedDiscCache、BaseImageDecoder、LruMemoryCache、SimpleBitmapDisplayer

UIL_Flow

ImageDownloader

接口

public interface ImageDownloader {
    InputStream getStream(String var1, Object var2) throws IOException;
    //返回Schema
    public static enum Schema{...}
}

基本实现

public class BaseImageDownloader implements ImageDownloader {
    //...
    //通过URL来从不同地方获取图片资源
    public InputStream getStream(String imageUri, Object extra) throws IOException {
    switch(...) {
    case 1:
    case 2:
        return this.getStreamFromNetwork(imageUri, extra);
    case 3:
        return this.getStreamFromFile(imageUri, extra);
    case 4:
        return this.getStreamFromContent(imageUri, extra);
    case 5:
        return this.getStreamFromAssets(imageUri, extra);
    case 6:
        return this.getStreamFromDrawable(imageUri, extra);
    case 7:
    default:
        return this.getStreamFromOtherSource(imageUri, extra);
    }
}
    //网络请求逻辑
    protected InputStream getStreamFromNetwork(String imageUri, Object extra) throws IOException {
    HttpURLConnection conn = this.createConnection(imageUri, extra);
    for(int redirectCount = 0; conn.getResponseCode() / 100 == 3 && redirectCount < 5; ++redirectCount) {
        conn = this.createConnection(conn.getHeaderField("Location"), extra);
    }
    InputStream imageStream;
    try {
        imageStream = conn.getInputStream();
    } catch (IOException var7) {
        IoUtils.readAndCloseStream(conn.getErrorStream());
        throw var7;
    }
    if(!this.shouldBeProcessed(conn)) {
        IoUtils.closeSilently(imageStream);
        throw new IOException("Image request failed with response code " + conn.getResponseCode());
    } else {
        return new ContentLengthInputStream(new BufferedInputStream(imageStream, '耀'), conn.getContentLength());
    }
}
//...
//创建Http请求对象
protected HttpURLConnection createConnection(String url, Object extra) throws IOException {
    String encodedUrl = Uri.encode(url, "@#&=*+-_.,:!?()/~\'%");
    HttpURLConnection conn = (HttpURLConnection)(new URL(encodedUrl)).openConnection();
    conn.setConnectTimeout(this.connectTimeout);
    conn.setReadTimeout(this.readTimeout);
    return conn;
}
}

磁盘缓存

接口

public interface DiskCache {
    File getDirectory();

    File get(String var1);

    boolean save(String var1, InputStream var2, CopyListener var3) throws IOException;

    boolean save(String var1, Bitmap var2) throws IOException;

    boolean remove(String var1);

    void close();

    void clear();
}

基本实现

  • BaseDiskCache (LimitedAgeDiskCache、UnlimitedDiskCache)
  • LruDiskCache

图片解码

接口

public interface ImageDecoder {
    Bitmap decode(ImageDecodingInfo var1) 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 class BaseImageDecoder implements ImageDecoder {
    ...
    public BaseImageDecoder(boolean loggingEnabled) {
        this.loggingEnabled = loggingEnabled;
    }

    public Bitmap decode(ImageDecodingInfo decodingInfo) throws IOException {
        //通过decodingInfo里面的downloader获取图片流
        InputStream imageStream = this.getImageStream(decodingInfo);
        if(imageStream == null) {
            L.e("No stream for image [%s]", new Object[]{decodingInfo.getImageKey()});
            return null;
        } else {
            Bitmap decodedBitmap;
            BaseImageDecoder.ImageFileInfo imageInfo;
            try {
                imageInfo = this.defineImageSizeAndRotation(imageStream, decodingInfo);
                imageStream = this.resetStream(imageStream, decodingInfo);
                Options decodingOptions = this.prepareDecodingOptions(imageInfo.imageSize, decodingInfo);
                decodedBitmap = BitmapFactory.decodeStream(imageStream, (Rect)null, decodingOptions);
            } finally {
                IoUtils.closeSilently(imageStream);
            }

            if(decodedBitmap == null) {
                L.e("Image can\'t be decoded [%s]", new Object[]{decodingInfo.getImageKey()});
            } else {
                decodedBitmap = this.considerExactScaleAndOrientatiton(decodedBitmap, decodingInfo, imageInfo.exif.rotation, imageInfo.exif.flipHorizontal);
            }

            return decodedBitmap;
        }
    }
    ....
}

内存缓存

接口

public interface MemoryCache {
    boolean put(String var1, Bitmap var2);

    Bitmap get(String var1);

    Bitmap remove(String var1);

    Collection<String> keys();

    void clear();
}

基本实现

public class LruMemoryCache implements MemoryCache {
    private final LinkedHashMap<String, Bitmap> map;
    private final int maxSize;
    private int size;

    public LruMemoryCache(int maxSize) {
        if(maxSize <= 0) {
            throw new IllegalArgumentException("maxSize <= 0");
        } else {
            this.maxSize = maxSize;
            this.map = new LinkedHashMap(0, 0.75F, true);
        }
    }

    public final Bitmap get(String key) {
        if(key == null) {
            throw new NullPointerException("key == null");
        } else {
            synchronized(this) {
                return (Bitmap)this.map.get(key);
            }
        }
    }

    public final boolean put(String key, Bitmap value) {
        if(key != null && value != null) {
            synchronized(this) {
                this.size += this.sizeOf(key, value);
                Bitmap previous = (Bitmap)this.map.put(key, value);
                if(previous != null) {
                    this.size -= this.sizeOf(key, previous);
                }
            }

            this.trimToSize(this.maxSize);
            return true;
        } else {
            throw new NullPointerException("key == null || value == null");
        }
    }

    private void trimToSize(int maxSize) {
        while(true) {
            synchronized(this) {
                if(this.size < 0 || this.map.isEmpty() && this.size != 0) {
                    throw new IllegalStateException(this.getClass().getName() + ".sizeOf() is reporting inconsistent results!");
                }

                if(this.size > maxSize && !this.map.isEmpty()) {
                    Entry toEvict = (Entry)this.map.entrySet().iterator().next();
                    if(toEvict != null) {
                        String key = (String)toEvict.getKey();
                        Bitmap value = (Bitmap)toEvict.getValue();
                        this.map.remove(key);
                        this.size -= this.sizeOf(key, value);
                        continue;
                    }
                }

                return;
            }
        }
    }

    public final Bitmap remove(String key) {
        if(key == null) {
            throw new NullPointerException("key == null");
        } else {
            synchronized(this) {
                Bitmap previous = (Bitmap)this.map.remove(key);
                if(previous != null) {
                    this.size -= this.sizeOf(key, previous);
                }

                return previous;
            }
        }
    }

    public Collection<String> keys() {
        synchronized(this) {
            return new HashSet(this.map.keySet());
        }
    }

    public void clear() {
        this.trimToSize(-1);
    }

    private int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }

    public final synchronized String toString() {
        return String.format("LruCache[maxSize=%d]", new Object[]{Integer.valueOf(this.maxSize)});
    }
}

图片显示器

定义图片显示效果,形状或动画,很nice

接口

public interface BitmapDisplayer {
    void display(Bitmap var1, ImageAware var2, LoadedFrom var3);
}

其中LoadedFrom代表图片加载的位置

public enum LoadedFrom {
    NETWORK,
    DISC_CACHE,
    MEMORY_CACHE;

    private LoadedFrom() {
    }
}

基本实现

无特效

public final class SimpleBitmapDisplayer implements BitmapDisplayer {
    public SimpleBitmapDisplayer() {
    }

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

圆形

好好学习,内部自定义了一个CircleDrawable

public class CircleBitmapDisplayer implements BitmapDisplayer {
    protected final Integer strokeColor;
    protected final float strokeWidth;

    public CircleBitmapDisplayer() {
        this((Integer)null);
    }

    public CircleBitmapDisplayer(Integer strokeColor) {
        this(strokeColor, 0.0F);
    }

    public CircleBitmapDisplayer(Integer strokeColor, float strokeWidth) {
        this.strokeColor = strokeColor;
        this.strokeWidth = strokeWidth;
    }

    public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
        if(!(imageAware instanceof ImageViewAware)) {
            throw new IllegalArgumentException("ImageAware should wrap ImageView. ImageViewAware is expected.");
        } else {
            imageAware.setImageDrawable(new CircleBitmapDisplayer.CircleDrawable(bitmap, this.strokeColor, this.strokeWidth));
        }
    }

    public static class CircleDrawable extends Drawable {
        protected float radius;
        protected final RectF mRect = new RectF();
        protected final RectF mBitmapRect;
        protected final BitmapShader bitmapShader;
        protected final Paint paint;
        protected final Paint strokePaint;
        protected final float strokeWidth;
        protected float strokeRadius;

        public CircleDrawable(Bitmap bitmap, Integer strokeColor, float strokeWidth) {
            this.radius = (float)(Math.min(bitmap.getWidth(), bitmap.getHeight()) / 2);
            this.bitmapShader = new BitmapShader(bitmap, TileMode.CLAMP, TileMode.CLAMP);
            this.mBitmapRect = new RectF(0.0F, 0.0F, (float)bitmap.getWidth(), (float)bitmap.getHeight());
            this.paint = new Paint();
            this.paint.setAntiAlias(true);
            this.paint.setShader(this.bitmapShader);
            this.paint.setFilterBitmap(true);
            this.paint.setDither(true);
            if(strokeColor == null) {
                this.strokePaint = null;
            } else {
                this.strokePaint = new Paint();
                this.strokePaint.setStyle(Style.STROKE);
                this.strokePaint.setColor(strokeColor.intValue());
                this.strokePaint.setStrokeWidth(strokeWidth);
                this.strokePaint.setAntiAlias(true);
            }

            this.strokeWidth = strokeWidth;
            this.strokeRadius = this.radius - strokeWidth / 2.0F;
        }

        protected void onBoundsChange(Rect bounds) {
            super.onBoundsChange(bounds);
            this.mRect.set(0.0F, 0.0F, (float)bounds.width(), (float)bounds.height());
            this.radius = (float)(Math.min(bounds.width(), bounds.height()) / 2);
            this.strokeRadius = this.radius - this.strokeWidth / 2.0F;
            Matrix shaderMatrix = new Matrix();
            shaderMatrix.setRectToRect(this.mBitmapRect, this.mRect, ScaleToFit.FILL);
            this.bitmapShader.setLocalMatrix(shaderMatrix);
        }

        public void draw(Canvas canvas) {
            canvas.drawCircle(this.radius, this.radius, this.radius, this.paint);
            if(this.strokePaint != null) {
                canvas.drawCircle(this.radius, this.radius, this.strokeRadius, this.strokePaint);
            }

        }

        public int getOpacity() {
            return -3;
        }

        public void setAlpha(int alpha) {
            this.paint.setAlpha(alpha);
        }

        public void setColorFilter(ColorFilter cf) {
            this.paint.setColorFilter(cf);
        }
    }
}

渐入动画

public class FadeInBitmapDisplayer implements BitmapDisplayer {
    private final int durationMillis;
    private final boolean animateFromNetwork;
    private final boolean animateFromDisk;
    private final boolean animateFromMemory;

    public FadeInBitmapDisplayer(int durationMillis) {
        this(durationMillis, true, true, true);
    }

    public FadeInBitmapDisplayer(int durationMillis, boolean animateFromNetwork, boolean animateFromDisk, boolean animateFromMemory) {
        this.durationMillis = durationMillis;
        this.animateFromNetwork = animateFromNetwork;
        this.animateFromDisk = animateFromDisk;
        this.animateFromMemory = animateFromMemory;
    }

    public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
        imageAware.setImageBitmap(bitmap);
        if(this.animateFromNetwork && loadedFrom == LoadedFrom.NETWORK || this.animateFromDisk && loadedFrom == LoadedFrom.DISC_CACHE || this.animateFromMemory && loadedFrom == LoadedFrom.MEMORY_CACHE) {
            animate(imageAware.getWrappedView(), this.durationMillis);
        }

    }

    public static void animate(View imageView, int durationMillis) {
        if(imageView != null) {
            AlphaAnimation fadeImage = new AlphaAnimation(0.0F, 1.0F);
            fadeImage.setDuration((long)durationMillis);
            fadeImage.setInterpolator(new DecelerateInterpolator());
            imageView.startAnimation(fadeImage);
        }

    }
}

处理逻辑

入口

//所有的同步加载、异步加载、有回调的、没回调的都会最终调用这个方法
public void displayImage(String uri, ImageAware imageAware, DisplayImageOptions options, ImageSize targetSize, ImageLoadingListener listener, ImageLoadingProgressListener progressListene
    //在这检查是否init ImageLoderConfiguration
    this.checkConfiguration();
    //封装了ImageView的属性和操作
    if(imageAware == null) {
        throw new IllegalArgumentException("Wrong arguments were passed to displayImage() method (ImageView reference must not be null)");
    } else {
        if(listener == null) {
            //默认为SimpleLoadingListener
            listener = this.defaultListener;
        }
        if(options == null) {
            //如果不设置图片显示属性,则使用默认值
            options = this.configuration.defaultDisplayImageOptions;
        }
        //图片URL为空
        if(TextUtils.isEmpty(uri)) {
            this.engine.cancelDisplayTaskFor(imageAware);
            listener.onLoadingStarted(uri, imageAware.getWrappedView());
            //是否设置图片URL为空时要设置的图片
            if(options.shouldShowImageForEmptyUri()) {
                imageAware.setImageDrawable(options.getImageForEmptyUri(this.configuration.resources));
            } else {
                imageAware.setImageDrawable((Drawable)null);
            }
            listener.onLoadingComplete(uri, imageAware.getWrappedView(), (Bitmap)null);
        } else {
            //图片URL不为空的情况
            //没有特别设置图片显示尺寸的话,显示最大尺寸
            if(targetSize == null) {
                targetSize = ImageSizeUtils.defineTargetSizeForView(imageAware, this.configuration.getMaxImageSize());
            }
            //通过尺寸和URL生成内存缓存的键值
            String memoryCacheKey = MemoryCacheUtils.generateKey(uri, targetSize);
            this.engine.prepareDisplayTaskFor(imageAware, memoryCacheKey);
            listener.onLoadingStarted(uri, imageAware.getWrappedView());
            //试图取出图片缓存
            Bitmap bmp = this.configuration.memoryCache.get(memoryCacheKey);
            ImageLoadingInfo imageLoadingInfo;
            //有图片缓存&&bitmap没有被回收
            if(bmp != null && !bmp.isRecycled()) {
                L.d("Load image from memory cache [%s]", new Object[]{memoryCacheKey});
                //是否要对图片进行特殊处理,比如加水印什么的(主要实现接口为BitmapProcessor)
                if(options.shouldPostProcess()) {
                    //把图片加载的配置信息封装起来
                    imageLoadingInfo = new ImageLoadingInfo(uri, imageAware, targetSize, memoryCacheKey, options, listener, progressListener, this.engine.getLockForUri(uri));
                    //Runnable类型的处理显示图片的任务,其实还是用调用LoadAndDisplayImageTask来执行的
                    ProcessAndDisplayImageTask displayTask1 = new ProcessAndDisplayImageTask(this.engine, bmp, imageLoadingInfo, defineHandler(options));
                    if(options.isSyncLoading()) {
                        //同步加载
                        displayTask1.run();
                    } else {
                        //异步加载,提交到线程池
                        this.engine.submit(displayTask1);
                    }
                } else {
                    //图片不需要特殊处理
                    //使用显示器显示,默认的实现(SimpleBitmapDisplayer)就是imageAware.setImageBirmap
                    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));
                //新建加载和显示任务,也是Runnable类型的
                LoadAndDisplayImageTask displayTask = new LoadAndDisplayImageTask(this.engine, imageLoadingInfo, defineHandler(options));
                if(options.isSyncLoading()) {
                    displayTask.run();
                } else {
                    this.engine.submit(displayTask);
                }
            }
        }
    }

任务类型

处理和显示

图片在内存已缓存,执行此任务

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 void run() {
        L.d("PostProcess image before displaying [%s]", new Object[]{this.imageLoadingInfo.memoryCacheKey});
        BitmapProcessor processor = this.imageLoadingInfo.options.getPostProcessor();
        Bitmap processedBitmap = processor.process(this.bitmap);
        DisplayBitmapTask displayBitmapTask = new DisplayBitmapTask(processedBitmap, this.imageLoadingInfo, this.engine, LoadedFrom.MEMORY_CACHE);
        LoadAndDisplayImageTask.runTask(displayBitmapTask, this.imageLoadingInfo.options.isSyncLoading(), this.handler, this.engine);
    }
}

加载和(处理和)显示

LoadAndDisplayImageTask,代码太多就不贴出来了,简单捋下逻辑:
1. 在run方法里面判断内存中是否有缓存,否则调用tryLoadBitmap
2. tryLoadBitmap首先判断磁盘是否有缓存,有则调用decodeImage返回Bitmap(经过以上分析,其实是调用了ImageDecoder,而在decoder里面又会调用ImageDowloader的getStream获得要解码的图片流)
3. 如果磁盘没有缓存,则调用网络获取图片流

执行引擎

从磁盘、网络加载图片等都是耗时操作,需要使用线程池执行操作。ImageLoaderEngine,顾名思义为UIL的整个动力源,没错它里面有三个线程池。

class ImageLoaderEngine {
    //分发任务,在run里面分发不同任务到下面两个线程池
    private Executor taskExecutor;
    //执行ProcessAndDisplayImageTask任务,从缓存(磁盘、内存)里面读
    private Executor taskExecutorForCachedImages;
    //执行LoadAndDisplayImageTask,从网络读
    private Executor taskDistributor;
    //...

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

相关阅读:UIL源码解析

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章