通过简单画的几张图来解释Glide中对于Gif的解析:
在加载到Gif相关的Stream流后,会回调到DecodeJob
中,然后经过LoadPath
到DecodePath
,具体的方法执行如下面的时序图。
在对应方法的回调过程中会根据返回的Stream来获取对应的
DecodePath
和其中保存的ResourceDecoder
。ResourceDecoder
表示Stream对应的解码器,会通过调用对应的handle方法来判断是否能够处理数据,然后在调用decode方法实现解码。
Gif首次解码时会执行到ByteBufferGifDecoder
中,简单看下源码:
@Override
public GifDrawableResource decode(
@NonNull ByteBuffer source, int width, int height, @NonNull Options options) {
// 这里的GifHeaderParser用于解码Gif相关的信息,比如header、帧数据、帧数等
final GifHeaderParser parser = parserPool.obtain(source);
try {
return decode(source, width, height, parser, options);
} finally {
parserPool.release(parser);
}
}
@Nullable
private GifDrawableResource decode(
ByteBuffer byteBuffer, int width, int height, GifHeaderParser parser, Options options) {
long startTime = LogTime.getLogTime();
try {
final GifHeader header = parser.parseHeader();
if (header.getNumFrames() <= 0 || header.getStatus() != GifDecoder.STATUS_OK) {
// If we couldn't decode the GIF, we will end up with a frame count of 0.
return null;
}
Bitmap.Config config =
options.get(GifOptions.DECODE_FORMAT) == DecodeFormat.PREFER_RGB_565
? Bitmap.Config.RGB_565
: Bitmap.Config.ARGB_8888;
int sampleSize = getSampleSize(header, width, height);
// 创建一个StandardGifDecoder用于读取GIF源中的帧数据
GifDecoder gifDecoder = gifDecoderFactory.build(provider, header, byteBuffer, sampleSize);
gifDecoder.setDefaultBitmapConfig(config);
// advance表示跳到下一帧的index
gifDecoder.advance();
// getNextFrame返回下一帧数据
Bitmap firstFrame = gifDecoder.getNextFrame();
if (firstFrame == null) {
return null;
}
Transformation<Bitmap> unitTransformation = UnitTransformation.get();
// 继承自Drawable,获取到下一帧数据后,会通过刷新View执行到Drawable的draw方法中,通过gifDecoder获取帧数据并绘制
GifDrawable gifDrawable =
new GifDrawable(context, gifDecoder, unitTransformation, width, height, firstFrame);
// 返回Resource,回调给上层,最终会返回到ImageViewTarget中
return new GifDrawableResource(gifDrawable);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Decoded GIF from stream in " + LogTime.getElapsedMillis(startTime));
}
}
}
StandardGifDecoder
解码GIF源数据并保存对应的index,来维持动画的目的。在GifDrawable中会创建GifFrameLoader
,GifFrameLoader负责循环的加载下一帧数据,然后回调到GifDrawable中刷新Drawable,具体的流程图如下所示:
在GifFrameLoader中加载下一帧时,会创建一个完整的请求流程来加载数据,和普通的请求区别在于,Gif的下一帧请求会将StandardGifDecoder作为参数传递给下一次请求的整个流程,用来获取对应的解码器GifFrameResourceDecoder
,具体的流程如下所示: