距上篇Glide分析的文章已經一個月了,實際分析起來Glide很複雜,對這種複雜進行形容的話,那就是「成噸的複雜」一點也不爲過。
沒看過上篇的小夥伴能夠看下git
Android圖片加載庫Glide 知其然知其因此然 開篇 github
此次我從Glide的建立開始談起,而後着重聊下, DataLoader這個環節,在此以前咱們先搞明白,Glide是怎樣把圖片加載這個過程拆分解耦的。先說結論他的加加載主要分爲這樣幾個過程:去作Model轉Data 、Data轉Resource、Resource互轉工做的類分別是一次分別是ModelLoader<Model, Data> 、ResourceDecoder<T, Z>以及ResourceTranscoder<Z, R> 接口的實現。數組
另外有了解碼也就是從文件、url、等解析成資源的過程也會設計到將Resource轉成Flile文件的過程,作這個工做的interface Encoder 接口的實現類。緩存
想必你們都據說過「高內聚,低耦合」,「上層不該該依賴於底層而是應該依賴與抽象」這樣的說法。 Glide把剛剛上面我描述的這些功能採用了一種註冊機制進行架構。在Glide的這個類構造方法裏有這些的代碼bash
Glide(...){
registry
//將byteBuffer轉換爲Flile
.append(ByteBuffer.class, new ByteBufferEncoder())
//將inputStream轉換爲File
.append(InputStream.class, new StreamEncoder(arrayPool))
/* Bitmaps */
//ByteBuffer解碼成Bitmap :decoderRegistry
.append(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, byteBufferBitmapDecoder)
....
/* BitmapDrawables */
.append(
Registry.BUCKET_BITMAP_DRAWABLE,
ByteBuffer.class,
BitmapDrawable.class,
new BitmapDrawableDecoder<>(resources, byteBufferBitmapDecoder))
/* GIFs */
.append(
Registry.BUCKET_GIF,
InputStream.class,
GifDrawable.class,
new StreamGifDecoder(imageHeaderParsers, byteBufferGifDecoder, arrayPool))
/* Files */
.append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())
FileLoader.FileDescriptorFactory())
// Compilation with Gradle requires the type to be specified for UnitModelLoader here.
.append(File.class, File.class, UnitModelLoader.Factory.<File>getInstance())
/* Models */
.register(new InputStreamRewinder.Factory(arrayPool))
.append(int.class, InputStream.class, resourceLoaderStreamFactory)
.append(
int.class,
ParcelFileDescriptor.class,
resourceLoaderFileDescriptorFactory)
.append(Integer.class, InputStream.class, resourceLoaderStreamFactory)
...
/* Transcoders */
.register(
Bitmap.class,
BitmapDrawable.class,
new BitmapDrawableTranscoder(resources))
.register(Bitmap.class, byte[].class, bitmapBytesTranscoder)
.register(
Drawable.class,
byte[].class,
new DrawableBytesTranscoder(
bitmapPool, bitmapBytesTranscoder, gifDrawableBytesTranscoder))
.register(GifDrawable.class, byte[].class, gifDrawableBytesTranscoder);
}
複製代碼
代碼實在太長我刪減的一部分,整體來說,他就是往裏註冊了ModuleLoader、Encoder、Decoder、Transcoder這四種組件,使其具有轉換模型數據,解析String url等源,解析加載bitmap drawable file用的Decoder,對資源進行轉碼的Transcoder,以及將資源轉成flile的Encoder。這些功能單元都被註冊在了Registry,這個類的註釋是這樣寫的,這其中的架構思想你們自行發散思考。網絡
Manages component registration to extend or replace Glide's default loading, decoding, and encoding logic.架構
言歸正傳,這篇咱們着重分析的就是Loading這個過程,抽象的講就是把複雜的Model(String Url 等)轉換成 Data(byte[] InputStream)過程。上面咱們知道了Loading在Glide整個系統中的位置,他的實現是怎樣的呢。app
做用將複雜多變抽象的Mode 如String URL 數據轉換爲直接被編碼的數據如byte[] inputStream等。ide
具體實現oop
public interface ModelLoader<Model, Data> {
class LoadData<Data> {
public final Key sourceKey;
public final List<Key> alternateKeys;
public final DataFetcher<Data> fetcher;
public LoadData(@NonNull Key sourceKey, @NonNull DataFetcher<Data> fetcher) {
this(sourceKey, Collections.<Key>emptyList(), fetcher);
}
public LoadData(@NonNull Key sourceKey, @NonNull List<Key> alternateKeys,
@NonNull DataFetcher<Data> fetcher) {
this.sourceKey = Preconditions.checkNotNull(sourceKey);
this.alternateKeys = Preconditions.checkNotNull(alternateKeys);
this.fetcher = Preconditions.checkNotNull(fetcher);
}
}
/** 給定model 寬高信息 已經Options生成LoadData<?> **/
@Nullable
LoadData<Data> buildLoadData(@NonNull Model model, int width, int height,
@NonNull Options options);
boolean handles(@NonNull Model model);
}
複製代碼
生產LoadDate的地方,LoadData裏面有個成員變量DataFetcher<>
這個類的對象是加載數據的實際負責人。
public interface DataFetcher<T> {
interface DataCallback<T> {
void onDataReady(@Nullable T data);
void onLoadFailed(@NonNull Exception e);
}
//加載資源文件,這些資源文件多是字節數組,文件等,都是用如今抽象T表明
void loadData(@NonNull Priority priority, @NonNull DataCallback<? super T> callback);
void cleanup();
void cancel();
@NonNull
Class<T> getDataClass();
@NonNull
DataSource getDataSource();
}
複製代碼
DataFetcher是一個泛型類,泛型T表示的就是要加載的Data類型。他的功能實現形式是經過回調的,回調接口DataCallback,DataCallback定義了兩個方法,onDataReady(T data)和onLoadFailed(Exception e); 見名知意,DataFetcher是獲取數據的抽象,他規定了獲取Data的時候是經過調用loadData這個方法,這個方法其中有一個參數是DataCallback,當Data獲取成功會調用callBack的onDataReady,當獲取失敗的使時候會調用onLoadFailed(Exception e)通知外界。
咱們在往Registry註冊Loader的時候,能夠清晰的看到其實往裏添加的主要是三個內容Class Class以及ModelLoaderFactory。沒錯ModelLoaderFactory就是構建ModelLoder的工廠類,前兩個參數指明瞭被處理的數據類型和加載成的數據類型。
.append(File.class, ByteBuffer.class, new ByteBufferFileLoader.Factory())
複製代碼
ModelLoaderFactory的代碼。
public interface ModelLoaderFactory<T, Y> {
ModelLoader<T, Y> build(@NonNull MultiModelLoaderFactory multiFactory);
void teardown();
}
複製代碼
值得注意是是在build方法中傳入了MultiModelLoaderFactory一看名字就不簡單啊,「多種模型加載工廠」,不貼代碼了真相是往Registry對象中註冊的ModelLoaderFactory最終都是保存在MultiModelLoaderFactory中的。
interface DataFetcherGenerator {
interface FetcherReadyCallback {
void reschedule();
void onDataFetcherReady(
Key sourceKey, @Nullable Object data,
DataFetcher<?> fetcher,DataSource dataSource,
Key attemptedKey);
void onDataFetcherFailed(Key attemptedKey, Exception e,
DataFetcher<?> fetcher,DataSource dataSource);
}
boolean startNext();
void cancel();
}
複製代碼
DataFetcherGenerator的集成類有三個
在已經註冊號的Modlerloader中查找處理
DecodeHelper{
...
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = modelLoaders.size(); i < size; i++) {
ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
LoadData<?> current =
modelLoader.buildLoadData(model, width, height, options);
if (current != null) {
loadData.add(current);
}
}
}
return loadData;
}
...
}
複製代碼
startNext方法
@Override
public boolean startNext() {
//當dataToCache不爲空的時候,將dataToCache放入內存中
//而後而後使用sourceCahceGenerator獲取Data
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
//獲取可以用的LoadData對象,而後調用它的LoadData()
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
複製代碼
SourceGenerator實現了DataCallBack接口
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything, we should // reschedule to get back onto Glide's thread.
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
複製代碼
獲取到數據能夠被緩存的狀況下就會將data賦值給dataToCache,若是不能被賦就回調傳入的FetcherReadyCallback對象的onReadyCallback方法。
Model轉Data也就是加載數據這個過程設計到單個核心接口類,ModelLoader、LoadData,DataFetcher。 LoadData是ModelLoader這個泛型接口的一個內部類,DataFetcher對象是ModelLoader的一個成員變量。實際將Model轉換成Data的工做者就是DataFetcher。
DataFetcher數據加載成功後,採用回調的方式通知調用它的對象。
完。