本篇本系列的最后一篇,概述和原理见另外两篇文章:
(一)Doodle - 精简的图片加载框架 - 概述篇
(二)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().addDrawableDecoders(GifDecoder)
}
注册了Gif解码器后,常规调用即可:如果图片源是GIF动图,会解码得到GifDrawable。
Doodle.load(path).into(imageView)
当然也可以指定不需要显示动图, 调用asBitmap方法即可。
四、Request (加载请求)
- 加载图片到View (ImageView或者自定义View)
Doodle.load(path).into(imageView)
- 通过接口回调result
Doodle.load(path).into(result -> {
if (result instanceof Bitmap) {
// handle bitmap
} else if (result instanceof Drawable) {
// handle drawable
} else {
// handle othe type (include null)
}
});
- 直接获取bitmap
Bitmap bitmap = Doodle.load(path).get()
- 预加载:
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) | 监听加载任务结束时有没有取到结果。 |