type
status
date
slug
summary
tags
category
icon
password
一个图片加载库应该具备的功能
- 图片下载
- 各种格式图片编解码
- 图片显示
- 缓存
- 图像处理:圆角,色调,调整大小等等
现在分析下Glide是如何实现这个图片加载库的,先来看一下Glide的主要模型
Glide内部模型
Target
Glide可以将一个
Resource
加载到Target
中,并在加载过程中通知相关生命周期事件.生命周期基本上是下面这个步骤:
- onLoadStarted
- onResourceReady / onLoadFailed
- onLoadCleared
但是这些步骤也不是绝对的.
如果resource在内存中或者model对象为null时,onLoadStarted不会被调用.
如果target不会被cleared,onLoadCleared也不会被调用.
使用得最多的就是ImageViewTarget了.ImageViewTarget是一个抽象类,它定义了一个抽象方法用于设置具体的资源:
它的子类就可以实现各自的资源设置方法,比如setBitmapResource(),setDrawable()之类的.
对于ViewTarget来说,会使用
View#setTag()
和View#getTagId()
方法在RecyclerView
或者其他ViewGroup
下存储一些信息,解决复用问题.ViewTarget中有一个方法
getSize()
,利用了ViewTreeObserver.OnPreDrawListener
时机去获取尺寸.目前源码中很多Target已经废弃,不推荐继承了,原因是因为
onLoadCleared()
,在使用资源的时候如果不clear()很容易导致问题.Request
表示 加载Resource到Target的过程.
RequestBuilder: 可以自定义各种属性,相当于Request的配置信息;
RequestManager: 创建和管理Request
Resource
在Glide中比较常见的是:
- Bitmap
- Drawable
- File
一个资源接口,用于包装资源以便于“池化”和重用.
比如BitmapResource:
使用了BitmapPool进行“池化”和回收.
Model
不知道怎么描述,可以是下面这些:
- 定义的实体类,比如UserInfo,这其中包含了图片url
- 一个简单的url
- File
- Uri
- 资源ID
Data
一般都是
InputStream
,也可以是File,也可以是byte[].Model/Data/Resource
ModelLoader
: 从Model 获取 DataDataFetcher
: 使用Data,以传递给其他模块进行下一步处理ResourceDecoder
: 将 Data 解码成 ResourceResourceDecoder
将 Data 解码 成 Resource , 比如将InputStream解码成Bitmap
ResourceEncoder
从Resource中取出Data,然后写入到一些持久化的数据存储中
比如 从Bitmap从取出字节流 ,写入到本地文件中.
Transformation
对Resource进行变换处理,即通常说的图片处理:
- CenterInside
- CenterCrop
- CircleCrop
- FitCenter
- Rotate
- RoundedCorners
- GranularRoundedCorners
与
ResourcTranscoder
在概念上的区别主要是:- Transformation不改变Resource的类型
- ResourceTranscoder改变资源的类型
ResourceTranscoder
将一种Resource转换成另一种Resource.
比如将Bitmap转换成Drawable,将Bitmap转换成byte[]等等.
Registry
Glide内部组件管理,像上面的ModelLoader,Encoder,Decoder在Registry中都有各自实现的Registry以进行注册和管理.
比如ResourceDecoderRegistry.
看完了模型定义,再来看图片库的功能.
下载
Android端目前网络请求基本上都是使用的OkHttp,我们使用Glide的时候一般也会使用OkHttp作为网络库.
在
OkHttpStreamFetcher
中有:请求成功之后,会得到一个InputStream:
这里将InputStream包装到ContentLengthInputStream中.
然后就是对InputStream中的字节流进行解码了.
编解码
对字节流解码的操作在
DecodeJob
中,这里的调用链比较长,具体的代码就不贴出来了.这里涉及的Decoder比较多,Glide会根据不同的图片格式使用不同的Decoder进行解码:
解码器 | 说明(---> 表示解码成) |
StreamGifDecoder | InputStream ---> ByteArray ---> GifDrawable |
InputStreamBitmapImageDecoderResourceDecoder | InputStream ---> Bitmap |
ByteBufferBitmapDecoder | ByteBuffer ---> Bitmap |
ResourceBitmapDecoder | Uri ---> Bitmap |
UnitDrawableDecoder | Drawable ---> Drawable |
ByteBufferGifDecoder | ByteBuffer ---> GifDrawable |
UnitBitmapDecoder | Bitmap ---> Bitmap |
GifFrameResourceDecoder | Gif Frame ---> Bitmap |
ParcelFileDescriptorBitmapDecoder | ParcelFileDescriptor ---> Bitmap |
FileDecoder | File ---> File |
SvgDecoder | InputStream ---> Svg |
StreamBitmapDecoder | InputStream ---> Bitmap |
ByteBufferBitmapImageDecoderResourceDecoder | ByteBuffer ---> Bitmap |
VideoDecoder | Video Frame ---> Bitmap |
ResourceDrawableDecoder | Uri ---> Drawable |
解码完成之后,就是资源类型之间的转换了:
Transcoder | 说明 |
BitmapDrawableTranscoder | Bitmap ---> BitmapDrawable |
SvgDrawableTranscoder | SVG. ---> Picture |
GifDrawableBytesTranscoder | GifDrawable ---> byte[] |
BitmapBytesTranscoder | Bitmap ---> byte[] |
DrawableBytesTranscoder | Drawable ---> byte[] |
像一般的图片显示,用到的是
StreamBitmapDecoder
,而它的解码实际上通过Downsampler
进行的,经过一系列的处理,比如获取图片宽高,缩放,旋转等,最后还是我们熟悉的API:图片显示
其实就是上面说到的Target,目前最常见的就是ViewTarget,ImageViewTarget.
在Target中调用系统的API,比如
setBitmapResource()
等进行设置显示图片:以及生命周期的管理.
缓存
在查看缓存策略之前,先看一下数据源的定义:
缓存策略定义在
DiskCacheStrategy
中,分为以下几种:- DiskCacheStrategy.ALL
缓存远程Data和Resource,以及本地的Resource
- DiskCacheStrategy.NONE
不缓存
- DiskCacheStrategy.DATA
在Data解码之前直接写到磁盘缓存
- DiskCacheStrategy.RESOURCE
将解码后的Resourc写入到磁盘缓存
- DiskCacheStrategy.AUTOMATIC
自动选择
图像处理
Transformation
中定义:- CenterInside
- CenterCrop
- CircleCrop
- FitCenter
- Rotate
- RoundedCorners
- GranularRoundedCorners
总结
- Glide软件模型比较清晰,代码结构也是严格按照这个模型来实现的;
- 图片加载的基本过程大同小异,但是期间也存在多处优化,比如内存占用方面的优化
- 生命周期的处理上,Glide自己用了回调参数去处理,其实如果集成了AndroidX Lifecycle的话,结构会更加清晰
- Glide结构虽然清晰,但是代码量其实很大的,很多细节之处并没有分析(分析起来估计得花不少时间)
- 后面会分析的有: Bitmap复用机制,图片缓存机制,编解码实际流程,不同类型图片的处理异同
- 作者:姜康
- 链接:https://jiangkang.tech/article/feff3823-f751-4767-8777-6c3977858b57
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。