ImageLoader详解(简单使用,源码分析,策略理解)

ImageLoader详解(简单使用,源码分析,策略理解)

整体流程

在这里插入图片描述

简单使用

ImageLoaderConfiguration:全局配置:主要有线程类、缓存大小、磁盘大小、图片下载与解析的配置。

DisplayImageOptions:与展示图片相关的配置

ImageLoader:具体执行类,最终通过displayImage方法执行

//DisplayImageOptions相关设置
DisplayImageOptions options = new DisplayImageOptions.Builder().showImageOnLoading(R.drawable.loading) 
                // 设置图片在下载期间显示的图片
                .showImageForEmptyUri(R.drawable.ic_launcher)
                // 设置图片Uri为空或是错误的时候显示的图片
                .showImageOnFail(R.drawable.error) 
                // 设置图片加载/解码过程中错误时候显示的图片
                .cacheInMemory(true)
                // 设置下载的图片是否缓存在内存中
                .cacheOnDisk(true)
                // 设置下载的图片是否缓存在SD卡中
                .considerExifParams(true) 
                // 是否考虑JPEG图像EXIF参数(旋转,翻转)
                .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
                // 设置图片以如何的编码方式显示
                .bitmapConfig(Bitmap.Config.RGB_565)
                // 设置图片的解码类型
                // .decodingOptions(BitmapFactory.Options decodingOptions)
                // 设置图片的解码配置
                .delayBeforeLoading(0)
                // int delayInMillis为你设置的下载前的延迟时间
                // 设置图片加入缓存前,对bitmap进行设置
                // .preProcessor(BitmapProcessor preProcessor)
                .resetViewBeforeLoading(true)
                // 设置图片在下载前是否重置,复位
                .displayer(new RoundedBitmapDisplayer(20))
                // 不推荐用!!!!是否设置为圆角,弧度为多少
                .displayer(new FadeInBitmapDisplayer(100))
                // 是否图片加载好后渐入的动画时间,可能会出现闪动
                .build();// 构建完成
//ImageLoaderConfiguration相关设置
ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context)
    	// 线程池内加载的数量
    	.threadPoolSize(3)
        // 线程优先级
        .threadPriority(Thread.NORM_PRIORITY - 2)
        // 不允许缓存一张图片的不同尺寸
        .denyCacheImageMultipleSizesInMemory()
        // 设置内存缓存,可以自定义实现
        .memoryCache(new UsingFreqLimitedMemoryCache(2 * 1024 * 1024))
        // 内存缓存最大值
        .memoryCacheSize(2 * 1024 * 1024)
        // 磁盘缓存最大值
        .diskCacheSize(50 * 1024 * 1024)
        // 磁盘缓存文件名生成器
        .diskCacheFileNameGenerator(new Md5FileNameGenerator())
        // 设置任务的执行顺序
        .tasksProcessingOrder(QueueProcessingType.LIFO)
        // 缓存的文件数量
        .diskCacheFileCount(100)
        // 默认的显示设置
        .defaultDisplayImageOptions(DisplayImageOptions.createSimple())
        // 设置加载器
        .imageDownloader(new BaseImageDownloader(context, 5 * 1000, 30 * 1000))
        // log
        .writeDebugLogs()
        // 开始构建
        .build();

//使用
ImageLoader.getInstance().init(config);
ImageLoader.getInstance().displayImage(bannerModel.getImageUrl(), imageView,options);

源码解析

包结构大致如下:仅对部分功能讲解

在这里插入图片描述

download包:封装了图片下载相关的方式
//ImageDownloader类中
public static enum Scheme {
    HTTP("http"),
    HTTPS("https"),
    FILE("file"),
    CONTENT("content"),
    ASSETS("assets"),
    DRAWABLE("drawable"),
    UNKNOWN("");

该接口中可以看到可以从网络,文件,content,assets目录,drawable目录去下载文件

BaseImageDownloader为具体实现类(SlowNetworkImageDownloader NetworkDeniedImageDownloader在其他目录,后面再讲)

public InputStream getStream(String imageUri, Object extra) throws IOException {
    switch(Scheme.ofUri(imageUri)) {
    case HTTP:
    case HTTPS:
            //网络资源从网络下载,重定向小于5次
        return this.getStreamFromNetwork(imageUri, extra);
    case FILE:
            //File资源从文件下载(为视频URi时使用视频缩略图)
        return this.getStreamFromFile(imageUri, extra);
    case CONTENT:
   //content资源通过contentresolver获得(为视频URi时使用视频缩略图,联系人的URI获取联系人缩略图)
        return this.getStreamFromContent(imageUri, extra);
    case ASSETS://Assert,drawable 资源正常获取。
        return this.getStreamFromAssets(imageUri, extra);
    case DRAWABLE:
        return this.getStreamFromDrawable(imageUri, extra);
    case UNKNOWN:
    default:
        return this.getStreamFromOtherSource(imageUri, extra);
    }
}
display包:封装简单的对展示图片的属性的处理(变圆形,圆角矩形,渐入动画,内阴影等)

通过实现自定义的Drawable,重写draw方法,使用BitmapShader将bitmap与paint绑定,将其绘制在自定义的不同形状的Canvas上,重写onBoundsChange方法,来控制绘制区域的大小,使其更合理的展示出来。

public class RoundedDrawable extends Drawable {
    protected final float cornerRadius;
    protected final int margin;
    protected final RectF mRect = new RectF();
    protected final RectF mBitmapRect;
    protected final BitmapShader bitmapShader;
    protected final Paint paint;

    /**
     *
     * @param bitmap
     * @param cornerRadius 圆角px
     * @param margin
     */
    public RoundedDrawable(Bitmap bitmap, int cornerRadius, int margin) {
        this.cornerRadius = (float) cornerRadius;
        this.margin = margin;
        this.bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
        this.mBitmapRect = new RectF((float) margin, (float) margin, (float) (bitmap.getWidth() - margin), (float) (bitmap.getHeight() - margin));
        this.paint = new Paint();
        this.paint.setAntiAlias(true); //开启抗锯齿,让图形和文字的边缘更加平滑
        this.paint.setShader(this.bitmapShader);
        this.paint.setFilterBitmap(true); //使用双线性过滤来绘制 Bitmap
        this.paint.setDither(true); //设置图像的抖动
    }

    protected void onBoundsChange(Rect bounds) {
        super.onBoundsChange(bounds);
        this.mRect.set((float) this.margin, (float) this.margin, (float) (bounds.width() - this.margin), (float) (bounds.height() - this.margin));
        Matrix shaderMatrix = new Matrix();
        shaderMatrix.setRectToRect(this.mBitmapRect, this.mRect, Matrix.ScaleToFit.FILL);
        this.bitmapShader.setLocalMatrix(shaderMatrix);
    }

    public void draw(Canvas canvas) {
        canvas.drawRoundRect(this.mRect, this.cornerRadius, this.cornerRadius, this.paint);
    }

    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

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

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

以圆角矩形(RoundedDrawable )为例,重写Drawable 的draw方法,通过canvas绘制一个圆角矩形,通过为画笔paint设置bitmapShader的方式,用bitmap来填充画布,来完成圆角矩形的绘制。其中,onBoundsChange方法用来对对图片的大小进行转换,使其可以合适的填充到mRect中。paint的setDither,setFilterBitmap,setAntiAlias可以简单的理解为在对图片进行美化,使其更加柔和的展示。

imageWare包:对ImageView的一层包装,方便内部扩展,如动画的效果。
protected void setImageDrawableInto(Drawable drawable, View view) {
    ((ImageView)view).setImageDrawable(drawable);
    if (drawable instanceof AnimationDrawable) {
        //此处开始动画
        ((AnimationDrawable)drawable).start();
    }
}

相关策略

网络下载策略

ImageLoader对不同的网络状态下处理下载策略是不同的,主要分为三种网络(正常、慢速、无网络权限),针对三种网络,实现了三种策略(BaseImageDownloader,SlowNetworkImageDownloader,NetworkDeniedImageDownloader )

BaseImageDownloader如上描述,处理正常网络情况以及其他的情况

SlowNetworkImageDownloader

private static class SlowNetworkImageDownloader implements ImageDownloader {
    private final ImageDownloader wrappedDownloader;

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

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

//FlushedInputStream类
public class FlushedInputStream extends FilterInputStream {
    public FlushedInputStream(InputStream inputStream) {
        super(inputStream);
    }

    public long skip(long n) throws IOException {
        long totalBytesSkipped;
        long bytesSkipped;
        for(totalBytesSkipped = 0L; totalBytesSkipped < n; totalBytesSkipped += bytesSkipped) {
            bytesSkipped = this.in.skip(n - totalBytesSkipped);
            if (bytesSkipped == 0L) {
                int by_te = this.read();
                if (by_te < 0) {
                    break;
                }
                bytesSkipped = 1L;
            }
        }
        return totalBytesSkipped;
    }
}

可见慢网情况下使用了FilterInputStream,重写了skip方法,具体的好处大家可以百度,这里就不过多解释了

NetworkDeniedImageDownloader

private static class NetworkDeniedImageDownloader implements ImageDownloader {
    private final ImageDownloader wrappedDownloader;

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

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

可见,在无权限的情况下,访问网络的直接抛异常,其他类型的则不影响处理

线程池策略

未完待续。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值