疑問
1.如何在圖片下載線程開始時做一個耗時處理
2.如何擴展支持webp動圖
a.分析gif的加載過程
b.分析webp的加載過程
版本
針對Glide以下版本分析
implementation "com.github.bumptech.glide:glide:4.11.0"
用法
Glide加載圖片最簡單的用法如下:
Glide.with(getContext())
.load("***")
.into(imageView);
完整流程
從網(wǎng)絡(luò)請求到顯示圖片完整流程大致如下:
注:以上未涉及Transformation等操作
DecoderJob::runWrapped中通過DataFetcherGenerator來指定網(wǎng)絡(luò)流懂扼、文件或本地資源DataFetcher
通過Fetcher獲取到數(shù)據(jù)流后則需要通過decoder實現(xiàn)解碼亚铁。
Decoder的注冊流程如下:
其中RegistersComponents接口使得Glide可以擴展其他decoder等實現(xiàn)侍郭。
在初始化時通過ManifestParser解析出已聲明的GlideModule,然后注冊到Registry药薯。
應(yīng)用程序和庫都可以注冊很多組件來擴展 Glide 的功能吉懊」舨保可用的組件包括:
- ModelLoader, 用于加載自定義的 Model(Url, Uri,任意的 POJO )和 Data(InputStreams, FileDescriptors)
- ResourceDecoder, 用于對新的 Resources(Drawables, Bitmaps)或新的 Data 類型(InputStreams, FileDescriptors)進(jìn)行解碼
- Encoder, 用于向 Glide 的磁盤緩存寫 Data (InputStreams, FileDesciptors)
- ResourceTranscoder腕窥,用于在不同的資源類型之間做轉(zhuǎn)換,例如炫狱,從 BitmapResource 轉(zhuǎn)換為 DrawableResource
- ResourceEncoder藻懒,用于向 Glide 的磁盤緩存寫 Resources(BitmapResource, DrawableResource)
Decoder注冊
以注冊Decoder為例,append方法參數(shù)中的dataClass视译、resourceClass分別代表什么束析?
/**
* Appends the given {@link ResourceDecoder} onto the list of available {@link ResourceDecoder}s
* in this bucket, allowing it to be used if all earlier and default {@link ResourceDecoder}s for
* the given types in this bucket fail (or there are none).
*
* <p>If you're attempting to replace an existing {@link ResourceDecoder} or would like to ensure
* that your {@link ResourceDecoder} gets the chance to run before an existing {@link
* ResourceDecoder}, use {@link #prepend(Class, Class, ResourceDecoder)}. This method is best for
* new types of resources and data or as a way to add an additional fallback decoder for an
* existing type of data.
*
* @see #prepend(String, Class, Class, ResourceDecoder)
* @see #setResourceDecoderBucketPriorityList(List)
* @param bucket The bucket identifier to add this decoder to.
* @param dataClass The data that will be decoded from ({@link java.io.InputStream}, {@link
* java.io.FileDescriptor} etc).
* @param resourceClass The resource that will be decoded to ({@link android.graphics.Bitmap},
* {@link com.bumptech.glide.load.resource.gif.GifDrawable} etc).
* @param decoder The {@link ResourceDecoder} to register.
*/
@NonNull
public <Data, TResource> Registry append(
@NonNull String bucket,
@NonNull Class<Data> dataClass,
@NonNull Class<TResource> resourceClass,
@NonNull ResourceDecoder<Data, TResource> decoder) {
decoderRegistry.append(bucket, decoder, dataClass, resourceClass);
return this;
}
registry
...
/* Bitmaps */
.append(
Registry.BUCKET_BITMAP,
ByteBuffer.class,
Bitmap.class,
byteBufferBitmapDecoder)
.append(
Registry.BUCKET_BITMAP,
InputStream.class,
Bitmap.class,
streamBitmapDecoder)
...
/* BitmapDrawables */
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ByteBuffer.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder))
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
InputStream.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, streamBitmapDecoder))
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ParcelFileDescriptor.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, parcelFileDescriptorVideoDecoder))
/* GIFs */
.append(
Registry.BUCKET_GIF,
InputStream.class,
GifDrawable.class,
new StreamGifDecoder(imageHeaderParsers, byteBufferGifDecoder, arrayPool))
.append(
Registry.BUCKET_GIF,
ByteBuffer.class,
GifDrawable.class,
byteBufferGifDecoder)
- bucket是解碼器類型的標(biāo)識KEY
- dataClass什么場景下是ByteBuffer、InputStream
從圖二可以看到data是由DataFetcher獲取的憎亚,不同的DataFetcher會返回不同的dataClass:
/** A DataFetcher that retrieves an {@link java.io.InputStream} for a Url. */
public class HttpUrlFetcher implements DataFetcher<InputStream> {
...
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
callback.onDataReady(result);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to load data for url", e);
}
callback.onLoadFailed(e);
} finally {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Finished http url fetcher fetch in " + LogTime.getElapsedMillis(startTime));
}
}
}
private static final class ByteBufferFetcher implements DataFetcher<ByteBuffer> {
...
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super ByteBuffer> callback) {
ByteBuffer result;
try {
result = ByteBufferUtil.fromFile(file);
} catch (IOException e) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
}
callback.onLoadFailed(e);
return;
}
callback.onDataReady(result);
}
- resourceClass什么場景使用
在使用Glide加載圖片時是可以指定resourceClass類型员寇,如下:
// 未指定時默認(rèn)配置
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public RequestBuilder<Bitmap> asBitmap() {
return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
}
public RequestBuilder<GifDrawable> asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
- 如何匹配上合適的decoder
Glide.with(getContext())
.load("***.webp")
.into(imageView);
如以上代碼dataClass為InputStream、resourceClass為Drawable
在圖二流程getDecodePaths中就會根據(jù)已關(guān)聯(lián)的dataClass第美、resourceClass匹配已注冊的decoder
public synchronized <T, R> List<ResourceDecoder<T, R>> getDecoders(
@NonNull Class<T> dataClass, @NonNull Class<R> resourceClass) {
List<ResourceDecoder<T, R>> result = new ArrayList<>();
for (String bucket : bucketPriorityList) {
List<Entry<?, ?>> entries = decoders.get(bucket);
if (entries == null) {
continue;
}
for (Entry<?, ?> entry : entries) {
if (entry.handles(dataClass, resourceClass)) {
result.add((ResourceDecoder<T, R>) entry.decoder);
}
}
}
// TODO: cache result list.
return result;
}
在圖二流程loadWithExceptionList中蝶锋,會按注冊順序嘗試decode,成功則返回decode結(jié)果什往,結(jié)束decode流程扳缕。
- 在圖四的Decoder的注冊流程中,有一處registerComponents可以注冊定制組件
在 Registry 類中定義了 prepend() , append() 和 replace() 方法,它們可以用于設(shè)置 Glide每個 ModelLoader 和 ResourceDecoder 之間的順序躯舔。
prepend()
prepend() 將確保你的 ModelLoader 或 ResourceDecoder 先于之前注冊的其他組件并被首先執(zhí)行驴剔。
append()
append() 將確保你的 ModelLoader 或 ResourceDecoder 僅在 Glide 的默認(rèn)組件被嘗試后才會被調(diào)用。
replace()
replace() 將移除所有處理給定模型和數(shù)據(jù)類的 ModelLoaders粥庄,并添加你的 ModelLoader 來代替丧失。
- webp動圖插件實現(xiàn)流程簡圖