简单好用的图片加载框架 - 用法篇

286 阅读7分钟

本篇是“Doodle - 精简的图片加载框架”的最后一篇,主要是关于用法的。
简单好用的图片加载框架 - 概述篇
如何实现图片加载框架 - 原理篇

一、下载

implementation 'io.github.billywei01:doodle:2.1.0'

二、Doodle (框架入口)

方法描述
Config config()返回全局配置。
Request load(String)根据路径返回Request。
Request load(File)根据文件返回Request。
Request load(int)根据资源id返回Request。
Request load(Uri)根据Uri返回Request。
File downloadOnly(String)下载文件(不解码器)。注意不要在主线程调用此方法。
File getCacheFile(String)获取缓存好的文件,没有则返回null。
void cacheBitmap(String,Bitmap,Boolean)保存bitmap到缓存。
Bitmap getCacheBitmap(String): Bitmap?从缓存中取bitmap, 无则返回null。
void pauseRequests()暂停请求。
void resumeRequests()恢复请求。
void notifyPause(Object)发送pause事件。
void notifyResume(Object)发送resume事件。
void notifyDestroy(Object)发送destroy事件。
void trimMemory(int)缩减内存缓存。
void clearMemory()清除LruCache中的所有bitmap。

三、Config (全局配置)

全局配置的设置和Request类似,都是链式调用。

Doodle.config()
    .setLogger(Logger)
    .setExecutor(IOExecutor)
    .setHttpSourceFetcher(OkHttpSourceFetcher)
    .addAnimatedDecoders(GifDecoder)

全局配置中的各个选项都是可选的(可以不设置)。

方法描述
setExecutor(Executor executor)设置Executor。
APP中如果每个组件都创建自己的线程池并且保持核心线程不销毁,那整个APP的存活线程就很多了,容易导致OOM。
故此,编写框架的时候,最好留一个接口给调用者传入Executor, 这样APP可以统一管理线程,框架可以复用APP的线程池。
当然,Doodle内部会套队列来控制任务的并发量,具体做法原理篇有讲述。
setLogger(DLogger logger)设置Logger。通过Log可以观察一些运行情况,输出错误日志等。
setCachePath(String)设置结果缓存的存储路径。如果不设定,会默认在内部目录的cache目录下创建子目录。
setResultMaxCount(int)设置果缓存最大数量,默认8192。
setResultCapacity(long)设置结果缓存的容量,默认128M。
setSourceMaxCount(int)设置原图缓存最大数量,默认4096。
setSourceCapacity(long)设置原图缓存容量,默认256M。
setMemoryCacheCapacity(long)设置内存缓存的容量,默认为maxMemory的1/6。
setCompressFormat(Bitmap.CompressFormat)设置结果缓存的压缩格式。
如果不设定默认压缩格式,Doodle会根据解码格式(RGB_8888/RGB_565),文件类型,以及系统版本决定用哪一种压缩格式。
setHttpSourceFetcher(HttpSourceFetcher)Doodle内置了下载http文件的代码,用SDK自带的HttpURLConnection实现。
如果需要用自己的下载方法,实现HttpSourceFetcher并调此方法注入即可。
addDataParser(DataParser)添加DataParser,用于自定义数据获取。
addAnimatedDecoders(AnimatedDecoder)添加自定义AnimatedDecoder。
addBitmapDecoders(BitmapDecoder)添加自定义BitmapDecoder。

全局配置中的HttpSourceFetcher和自定义解码,这里展开讲一下:

  • HttpSourceFetcher HttpSourceFetcher的定义很简单,传入url, 返回InputStream,如果请求失败,抛IOException。
public interface HttpSourceFetcher {
    InputStream getInputStream(String url) throws IOException;
}

需要指出的是,Doodle自己实现了磁盘缓存(包括网络文件缓存),如果使用OkHttp实现下载HttpSourceFetcher,建议在请求的地方调用:

cacheControl(CacheControl.Builder().noStore().noCache().build())

以免缓存两份原文件。

  • 自定义解码 Doodle提供了两个自定义解码接口:
public Config addAnimatedDecoders(AnimatedDecoder decoder)
public Config addBitmapDecoders(BitmapDecoder decoder)

接口比较简单,传入解码信息(包括数据源信息以及目标解码参数,具体可参考源码),返回结果。
例如,AnimatedDecoder义如下:

public interface AnimatedDecoder {
    Object decode(DecodingInfo info);
}

如果需要支持解码GIF, 可以引入android-gif-drawable,实现DrawableDecoder接口。

import pl.droidsonroids.gif.GifDrawable

object GifDecoder : DrawableDecoder {
    override fun decode(info: DecodingInfo): Any? {
        if (info.mediaType != MediaType.GIF) {
            return null
        }
        val gifDrawable = GifDrawable(info.data)
        // 如果GIF文件只有一帧,可以返回Bitmap,那样下次加载就可以直接读缓存了。
        if (gifDrawable.numberOfFrames == 1) {
            return gifDrawable.currentFrame
        }
        return gifDrawable
    }
}

然后在APP初始化时注册:

fun initApplication(context: Application) {
      Doodle.config().addAnimatedDecoders(GifDecoder)
}

注册了Gif解码器后,常规调用即可:如果图片源是GIF动图,会解码得到GifDrawable。

Doodle.load(path).into(imageView)

当然也可以指定不需要显示动图, 调用asBitmap方法即可。

四、Request(加载请求)

Doodle加载图片的API和Picasso/Glide相似。

  1. 加载图片到View (ImageView或者自定义View)
Doodle.load(path).into(imageView)
  1. 通过接口回调result
Doodle.load(path).into(result -> {
    if (result instanceof Bitmap) {
        // handle bitmap
    } else if (result instanceof Drawable) {
        // handle drawable
    } else { 
        // handle null
    }
});
  1. 直接获取bitmap
Bitmap bitmap = Doodle.load(path).get()
  1. 预加载
Doodle.load(path).preload()

Doodle加载图片,从load()方法开始,到into(), get() 或者 preload()方法结束。 在into()/get()/preload()之前,可以添加更多的参数。

方法描述
sourceKey(String)设置数据源的key。
path默认情况下作为CacheKey的一部分,有时候path有动态的参数,使得path频繁变化,从而无法缓存。
此时可以取不变的部设置为sourceKey,替换path作为CacheKey的一部分。
override(int, int)指定目标尺寸。
scaleType(ImageView.ScaleType)指定缩放类型。
如果未设定,且target为ImageView,则会自动从ImageView获取。
clipType(ClipType)ClipType 是自定义缩放类型枚举,大部分和ScaleType重叠,有少量增删。
enableUpscale()默认情况下,解码图片文件基于降采样的方式。
例如:
目标宽高是200x200,目标scaleType='centerCrop'。
1、文件分辨率是400x400,最终会解码出200x200的bitmap;
2、文件分辨率是100x100,最终会解码出100x100的bitmap。
第2种情况,由于源文件本身的分辨率只有100x100, 当ImageView的scaleType是centerCrop时,正常解码100x100和上采样成200x200的显示结果是一样的,后者并不会比前者清晰。
但有的情况就是要不管源文件分辨率,要求最终解码出的bitmap是目标宽高,这时候可以调用此方法。
memoryCacheStrategy(MemoryCacheStrategy)设置内存缓存策略,默认LRU策略。
diskCacheStrategy(DiskCacheStrategy)设置磁盘缓存策略,默认ALL。
noCache()不做任何缓存,包括磁盘缓存和内存缓存。
onlyIfCached(boolean)指定网络请求是否只从缓存读取(原图缓存)。
decodeFormat(DecodeFormat)设置解码格式,默认ARGB_8888。
transform(Transformation)设置解码后的图片变换(圆形剪裁,圆角,灰度,模糊等),可以连续调用(会按顺序执行)。
Doodle内置了圆形剪裁和圆角两种Transfromation。
keepOriginalDrawable()默认情况下请求开始会先清空ImageView之前的Drawable, 调用此方法后会保留之前的Drawable,直到加载结束。
placeholder(int)设置占位图,在结果加载完成之前会显示此drawable。
placeholder(Drawable)同上。
error(int)设置加载失败后的占位图。
error(Drawable)同上。
animation(int)设置加载成功后的过渡动画。
animation(Animation)同上。
fadeIn(int)加载成功后显示淡入动画。
crossFade(int)这个动画效果是“原图”从透明度100到0, bitmap从0到100。
当设置placeholder时,placeholder为“原图”。
如果没有设置placeholder, 效果和fadeIn差不多。
需要注意的是,这个动画在原图和bitmap宽高不相等时,动画结束时图片会变形。
因此,慎用crossFade。
alwaysAnimation(Boolean)默认情况下仅在图片是从磁盘或者网络加载出来时才做动画,可通过此方法设置总是做动画。
asBitmap()当设置了GIF Decoder时,默认情况下只要图片是GIF图片,则用GIF Decoder解码。
调用此方法后,不走GIF解码器,直接用BitmapFactory解码,并返回bitmap。
observeHost(Object)传入宿主(Activity/Fragment/View), 以观察其生命周期。
addOption(String, String)options目前有两个作用:
1. 传递参数给自定义Decoder;
2. 参与计算CacheKey, 以区分不同请求。
setBitmapDecoder(BitmapDecoder)添加针对单个请求的BitmapDecoder。
此Decoder仅作用于当前Request, 并且会优先于其他自定义Decoder。
enableThumbnailDecoder()这个选项是用于加速相册缩略图显示的,只对相册媒体(路径开头为"content://media/external/")有效。
相册中的媒体文件通常伴有生成好的缩略图文件,读取缩略图文件要比读取原文件要快很多。
缩率图文件分辨率较低,用于自定义相册的列表显示足够了。
开启此选项,会优先尝试读取缩略图,如果读取不到则访问原文件。
此选项仅作用于当前Request。
listen(CompleteListener)监听加载任务结束时有没有取到结果(bitmap/drawable)。