基于 Gilde 4.3.1
Glide 是我非常喜歡使用的圖片加載框架比吭,這篇文章講從源碼的角度剖析 Glide 框架祈坠。
從而得知 Glide 為我們做了哪些工作双抽。
Glide 的使用參考文檔
ImageView imageView = findViewById(R.id.test);
ImgurGlide.with(getApplicationContext())
.load(imageUrl)
.into(imageView);
Glide 使用起來特別方便宣虾,一條鏈式調用就可以把圖片下載并顯示到 ImageView 上祈匙。
其中 ImgurGlide 是我們自定義的一個 AppGlideModule
@GlideModule(glideName = "ImgurGlide")
public class ImgurGlideModule extends AppGlideModule {
// Intentionally Empty.
}
ImgurGlide 的生成魏保,使用了 APT(Annotation Processing Tool)技術,這里先不做講述漂坏。ImgurGlide 的每個方法都是包裹了 Glide 靜態(tài)對象去實現(xiàn)景埃。
逐步分析
Glide.with(……)
Glide.with() 有下面幾種實現(xiàn)方式。
1. Glide.with(Context context)
2. Glide.with(Activity activity)
3. Glide.with(FragmentActivity activity)
4. Glide.with(android.app.Fragment fragment)
5. Glide.with(View view)
所以的方法實現(xiàn)也是很類似顶别,都是調用同一個方法
public static RequestManager with(Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
再看一下 getRetriever() 方法
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
……
省略一些判空檢查
——
return Glide.get(context).getRequestManagerRetriever();
}
其中 Glide.get(context) 主要用來初始化 Glide 的全局單利對象谷徙,以及一些配置。
getRequestManagerRetriever() 則是返回 Glide 對象的 requestManagerRetriever 對象驯绎。
然后看一下 requestManagerRetriever.get() 方法
public RequestManager get(Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
get() 方法會根據(jù)傳入的 context 對象和當前線程完慧,創(chuàng)建不同的 RequestManager 實例
1. 非 UI 線程,返回 applicationManager 對象剩失,能感知 Application 生命周期屈尼。
2. UI 線程册着,如果 context 是 Activity 、FragmentActivity
則會創(chuàng)建一個能感知對應 Activity 的 RequestManager脾歧。
3. UI 線程甲捏,如果 Context 是 Fragment、android.support.v4.app.Fragment
則會創(chuàng)建一個能感知對應 Fragment 生命周期 的 RequestManager鞭执。
這里反復提到了一個 感知生命 xx 周期
司顿,也是 Glide 的一個特性。
Glide 在加載資源的時候兄纺,如果是在 Activity大溜、Fragment 這一類有生命周期的組件上進行。
當 Activity估脆、Fragment 等組件進入不可見钦奋,或者已經(jīng)銷毀的時候,Glide 會停止加載資源疙赠。
Application 的生命周期貫穿整個應用锨苏,所以 applicationManager 只有在應用程序關閉的時候終止加載。
所以盡量不要在非 UI 線程使用 Glide 加載圖片棺聊,盡量使用 Activity、Fragment 等帶有生命周期的組件配合 Glide 使用贞谓。
Glide 如何獲得 Activity限佩、Fragment 生命周期回調
在 各種 requestManagerRetriever.get() 方法中如果傳入的是帶有生命周期的組件,并且在 UI 線程裸弦,會執(zhí)行以下幾個方法端
// FragmentActivity
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null /*parentHint*/);
//android.support.v4.app.Fragment
FragmentManager fm = fragment.getChildFragmentManager();
return supportFragmentGet(fragment.getActivity(), fm, fragment);
//Activity
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(activity, fm, null /*parentHint*/);
//android.app.Fragment
android.app.FragmentManager fm = fragment.getChildFragmentManager();
return fragmentGet(fragment.getActivity(), fm, fragment);
- 如果是 Activity 祟同,先獲取 FragmentManager ,如果是 Fragment 則先獲取 ChildFragmentManager理疙。
- 如果是 support 包下面的 Activity 晕城、Fragment 調用 supportFragmentGet,否則調用 fragmentGet窖贤。
fragmentGet() 和 supportFragmentGet() 方法大致類似砖顷,選取一個分析一下。
private RequestManager fragmentGet(Context context, android.app.FragmentManager fm,
android.app.Fragment parentHint) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
上面這段代碼做了兩個功能
1. 創(chuàng)建一個 RequestManagerFragment赃梧。
2. 創(chuàng)建一個 RequestManager滤蝠。
先看一下 getRequestManagerFragment
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
RequestManagerFragment getRequestManagerFragment(
final android.app.FragmentManager fm, android.app.Fragment parentHint) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
這是是 Glide 設計中比較一個巧妙的地方
創(chuàng)建一個透明的 RequestManagerFragment 加入到FragmentManager 之中
通過添加的這個 Fragment 感知 Activity 、Fragment 的生命周期授嘀。
在Fragment 源碼學習,從源碼理解 Fragment 生命周期中已經(jīng)說明物咳,添加到 Activity的 Fragment 會跟隨Activity的生命周期。
Fragment的 childFragment 則會通過 ChildFragmentManager 和 Fragment 保持生命周期一致蹄皱。
這里說一個細節(jié)
剛開始看這段代碼時览闰,看到 handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
……
case ID_REMOVE_FRAGMENT_MANAGER:
android.app.FragmentManager fm = (android.app.FragmentManager) message.obj;
key = fm;
removed = pendingRequestManagerFragments.remove(fm);
……
以為 Glide 添加了一個 Fragment 到 FragmentManager 中芯肤,然后又刪除了。為此困惑了好久压鉴。
在 Glide 的 github 里 issue#2289 才明白崖咨。
Glide 在添加 Fragment 到 FragmentManger 后,
再從 pendingRequestManagerFragments 中刪除 FragmentManager 晴弃。
并不是刪除 Fragment掩幢。
在 RequestManagerFragment 中可以看到以下代碼
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
專業(yè)就可以通過 RequestManagerFragment 把 Activity 的生命周期通過 lifecycle 傳遞給在 lifecycle 注冊的 LifecycleListener。
RequestManager.load(url)
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as(Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
return loadGeneric(model);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
以上就是 RequestBuilder.load(url) 的相關代碼上鞠,發(fā)現(xiàn)并沒有什么特殊之處际邻。 只是創(chuàng)建了一個 RequestBuilder 。
RequestBuilder.into(view)
into() 方法調用起來十分方便芍阎,只要傳遞一個 ImageView 世曾,Glide 就會自動下載圖片,并且顯示到 ImageView 上谴咸。這看似十分簡單的一步轮听,也是 Glide 最負責的調用。
public Target<TranscodeType> into(ImageView view) {
RequestOptions requestOptions = this.requestOptions;
……
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions);
}
跟蹤一下 glideContext.buildImageViewTarget(view, transcodeClass) 會發(fā)現(xiàn)這里返回的是一個DrawableImageViewTarget
into(ImageView view) 把 requestOptions 和 DrawableImageViewTarget 傳入
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
RequestOptions options) {
……
Request request = buildRequest(target, targetListener, options);
Request previous = target.getRequest();
……
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
下一步跟蹤到 requestManager.track(target, request)
void track(Target<?> target, Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
isPaused 變量
1. 如果此時 GlideRequests 的 Lifecycle 為 ApplicationLifecycle岭佳,只要應用存活
isPaused 為 false 血巍,直接執(zhí)行 request.begin()
2. 如果 GlideRequests 的 Lifecycle 是觀測 Fragment 或者 Activity
isPaused 為true ,不會立即執(zhí)行 request.begin()
當 Fragment 或者 Activity 顯示到前臺時通過遍歷 requests 數(shù)組執(zhí)行 request.begin()
所以執(zhí)行網(wǎng)絡請求下載圖片的操作在 request.begin()
之中。
回到 into(ImageView view) 方法的
Request request = buildRequest(target, targetListener, options)
經(jīng)過層層包裹我們可以找到一下路線珊随,發(fā)現(xiàn)最后返回的是 SingleRequest
buildRequest >> buildRequestRecursive >> buildThumbnailRequestRecursive
>> obtainRequest >> SingleRequest
創(chuàng)建 SingleRequest 的過程比較復雜述寡,牽扯到縮略圖、錯誤處理之類的邏輯叶洞,大致都是上面那條路徑鲫凶。
然后就看一下 SingleRequest.begin()
@Override
public void begin() {
……
省略一些其他分支
……
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
……
……
}
begin() 方法很長,我們剔除了一些異常處理衩辟,直接看最核心的方法螟炫。
如果我給 Glide 設置了 override() 則直接調用 onSizeReady(overrideWidth, overrideHeight)
否則會調用 target.getSize(this) 讓 ImageView 計算自己的尺寸。
glideContext.buildImageViewTarget(view, transcodeClass) 創(chuàng)建一個 DrawableImageViewTarget
先看一些 DrawableImageViewTarget 類的繼承關系圖
這個類圖關系中 SizeDeterminer.getSize(SizeReadyCallback cb)就是計算 ImageView 尺寸
void getSize(SizeReadyCallback cb) {
int currentWidth = getTargetWidth();
int currentHeight = getTargetHeight();
if (isViewStateAndSizeValid(currentWidth, currentHeight)) {
cb.onSizeReady(currentWidth, currentHeight);
return;
}
// We want to notify callbacks in the order they were added and we only expect one or two
// callbacks to be added a time, so a List is a reasonable choice.
if (!cbs.contains(cb)) {
cbs.add(cb);
}
if (layoutListener == null) {
ViewTreeObserver observer = view.getViewTreeObserver();
layoutListener = new SizeDeterminerLayoutListener(this);
observer.addOnPreDrawListener(layoutListener);
}
}
其中 getTargetWidth() 和 getTargetHeight()是用來計算 View 尺寸的艺晴,在 View 尺寸法傷改變的時候時候通過 SizeDeterminerLayoutListener 通知 SizeReadyCallback View 尺寸發(fā)生改變昼钻。
流程最終都會執(zhí)行 SingleRequest.onSizeReady(width, height) 方法
@Override
public void onSizeReady(int width, int height) {
……
loadStatus = engine.load(
glideContext,
model,
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),
transcodeClass,
priority,
requestOptions.getDiskCacheStrategy(),
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this);
……
}
看到一個新的對象 Engine 從字面意思上可以猜測好像是用來加載圖片用的,查看 engine.load()
public <R> LoadStatus load(……) {
……
如果資源已經(jīng)緩存封寞,直接調用 onResourceReady
……
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
……
EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
useUnlimitedSourceExecutorPool, useAnimationPool);
DecodeJob<R> decodeJob = decodeJobFactory.build(……);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
……
return new LoadStatus(cb, engineJob);
}
load() 方法很長换吧,上面只保留和核心的內容。
EngineJob 和 DecodeJob 是用來加載網(wǎng)絡資源的钥星,如果資源已經(jīng)存在沾瓦,不會重復加載。
先看下 cb.onResourceReady(active, DataSource.MEMORY_CACHE)
這里的 cb 就是 SingleRequest
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
……
……
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
……
try {
if (……) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
流程會跳轉到 target.onResourceReady(result, animation) ,target 就是 DrawableImageViewTarget
@Override
public void onResourceReady(Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
直接看 setResourceInternal(resource)
private void setResourceInternal(@Nullable Z resource) {
maybeUpdateAnimatable(resource);
setResource(resource);
}
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
以上終于看到 view.setImageDrawable(resource) 贯莺。
以上大致就是 ImgurGlide.with(getApplicationContext()).load(imageUrl).into(imageView) 的大致流程风喇,先總計如下。
Glide 從網(wǎng)絡下載圖片的流程更復雜缕探,后面重點講魂莫。
Glide 網(wǎng)絡加載圖片
Glide 網(wǎng)絡加載圖片比較負責,找了很久才找到做網(wǎng)絡請求的部分爹耗。這里單獨拉出來講耙考。
先回到 load() 方法。
public <R> LoadStatus load(……) {
……
如果資源已經(jīng)緩存潭兽,直接調用 onResourceReady
……
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
……
EngineJob<R> engineJob = engineJobFactory.build(key, isMemoryCacheable,
useUnlimitedSourceExecutorPool, useAnimationPool);
DecodeJob<R> decodeJob = decodeJobFactory.build(……);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
……
return new LoadStatus(cb, engineJob);
}
看一下 engineJob.start(decodeJob)
public void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
這里看到了線程池操作 這里有兩個線程池倦始,分別對象兩種緩存方式。有興趣可以去看下這兩種線程池的配置
Engine 的初始化在 GlideBuilder.build(Context context)
……
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor());
}
……
那 DecodeJob 肯定是負責加載圖片的了山卦,先看 DecodeJob.run()
public void run() {
……
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
}
……
}
正常情況下會執(zhí)行
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
這里可以看到有很多分析鞋邑,通過 Debug 可以知道這里走 INITIALIZE 拗踢。至于其他情況瞒渠,等著以后去研究吧。
private DataFetcherGenerator getNextGenerator() {
switch (stage) {
case RESOURCE_CACHE:
return new ResourceCacheGenerator(decodeHelper, this);
case DATA_CACHE:
return new DataCacheGenerator(decodeHelper, this);
case SOURCE:
return new SourceGenerator(decodeHelper, this);
case FINISHED:
return null;
default:
throw new IllegalStateException("Unrecognized stage: " + stage);
}
}
因為我們傳入的是一個 Url 地址几蜻,會走 SOURCE 分支铸本,返回一個 SourceGenerator肮雨。
接著執(zhí)行 runGenerators()
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// We've run out of stages and generators, give up.
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
// Otherwise a generator started a new load and we expect to be called back in
// onDataFetcherReady.
}
這里比較重要的是 while 循環(huán)條件里面的 currentGenerator.startNext()),即 SourceGenerator
@Override
public boolean startNext() {
……
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (……) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
這又出現(xiàn)了新的對象 loadData 并且執(zhí)行 loadData.fetcher.loadData(……)
看起來特別想是加載網(wǎng)絡圖片操作箱玷,但是這部分代碼有點不好理解酷含。
loadData 是什么?
fetcher 又是什么汪茧?
搞不清池這兩個對象是什么,根本沒法繼續(xù)跟進了O薹2瘴邸!
尋找 loadData
根據(jù) while 那段代碼判斷 helper.getLoadData() 似乎返回了不止一個 loadData 弥虐,所以需要循環(huán)遍歷每一個 loadData 找到能執(zhí)行 loadData.fetcher.loadData(helper.getPriority(), this)的對象扩灯。
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
int size = modelLoaders.size();
for (int i = 0; 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;
}
這里看出 DecodeHelper 對象遍歷 glideContext 的 Registry 對象,尋找匹配 model 的 ModelLoader
然后執(zhí)行 modelLoader.buildLoadData(model, width, height, options) 創(chuàng)建 LoadData 并添加到 List 返回霜瘪。
于是又引入兩個問題
ModelLoader 是啥玩意珠插?
modelLoader.buildLoadData() 做啥玩意?
啊~~~~~ 好頭疼S倍浴D沓拧!
繼續(xù)跟代碼
public <Model> List<ModelLoader<Model, ?>> getModelLoaders(Model model) {
List<ModelLoader<Model, ?>> result = modelLoaderRegistry.getModelLoaders(model);
if (result.isEmpty()) {
throw new NoModelLoaderAvailableException(model);
}
return result;
}
public synchronized <A> List<ModelLoader<A, ?>> getModelLoaders(A model) {
List<ModelLoader<A, ?>> modelLoaders = getModelLoadersForClass(getClass(model));
int size = modelLoaders.size();
List<ModelLoader<A, ?>> filteredLoaders = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
ModelLoader<A, ?> loader = modelLoaders.get(i);
if (loader.handles(model)) {
filteredLoaders.add(loader);
}
}
return filteredLoaders;
}
private <A> List<ModelLoader<A, ?>> getModelLoadersForClass(Class<A> modelClass) {
List<ModelLoader<A, ?>> loaders = cache.get(modelClass);
if (loaders == null) {
loaders = Collections.unmodifiableList(multiModelLoaderFactory.build(modelClass));
cache.put(modelClass, loaders);
}
return loaders;
}
以上方法似乎還是看不出什么,在這里糾結很久顾患。最后發(fā)現(xiàn)在 Glide 構造方法中有以下代碼
Glide(……) {
……
registry
.append(ByteBuffer.class, new ByteBufferEncoder())
.……
這里省略很多 append
……
.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory())
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
……
這里省略很多 append
……
}
append() 方法
public <Model, Data> Registry append(Class<Model> modelClass, Class<Data> dataClass,
ModelLoaderFactory<Model, Data> factory) {
modelLoaderRegistry.append(modelClass, dataClass, factory);
return this;
}
public synchronized <Model, Data> void append(Class<Model> modelClass, Class<Data> dataClass,
ModelLoaderFactory<Model, Data> factory) {
multiModelLoaderFactory.append(modelClass, dataClass, factory);
cache.clear();
}
到這里我們終于看到了一點陽光
Glide 注冊了很多 modelLoader
這些 modelLoader 就是加載各種資源用的
我們使用的字符串表示 URL 番捂,應該屬于 String 類型
.append(String.class, InputStream.class, new DataUrlLoader.StreamFactory())
.append(String.class, InputStream.class, new StringLoader.StreamFactory())
.append(String.class, ParcelFileDescriptor.class, new StringLoader.FileDescriptorFactory())
處理 String 類型的有三個,但是我們是網(wǎng)絡下載圖片所以可以排除第三個江解。
每一個 ModelLoader 對象都有一個
public boolean handles(String url) {
……
}
DataUrlLoader 的 handles 只接受 "data:image" 開頭的字符设预,所以只剩下 StringLoader。
這里直接說出了結果犁河,具體每一步的調用可以按照上面思路鳖枕,配合單步調試了解詳情
然后看下 StreamFactory 和 StringLoader.buildLoadData()
public static class StreamFactory implements ModelLoaderFactory<String, InputStream> {
@Override
public ModelLoader<String, InputStream> build(MultiModelLoaderFactory multiFactory) {
return new StringLoader<>(multiFactory.build(Uri.class, InputStream.class));
}
@Override
public void teardown() {
// Do nothing.
}
}
@Override
public LoadData<Data> buildLoadData(String model, int width, int height,
Options options) {
Uri uri = parseUri(model);
return uri == null ? null : uriLoader.buildLoadData(uri, width, height, options);
}
可以看到 StringLoader.buildLoadData() 又代理給了處理 <Uri.class, InputStream.class> 的 ModelLoader
然后在 Glide 的一堆 append 中找到對應的 UrlUriLoader.StreamFactory()
再次發(fā)現(xiàn),又代理給了 <GlideUrl.class, InputStream.class>,于是我們終于找到 HttpGlideUrlLoader 并且再沒有代理到其他 ModelLoader
Glide 的里面注冊很多 ModelLoader 只是一個包裹器桨螺,有具體操作的就幾種 ModelLoader
HttpGlideUrlLoader 是其中一個宾符。
HttpGlideUrlLoader 的 buildLoadData 返回了我們要找的 LoadData
public LoadData<InputStream> buildLoadData(GlideUrl model, int width, int height,
Options options) {
……
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
尋找 fetcher
找到 LoadData 的同時,我們也找到了 fetcher 即 HttpUrlFetcher
看名字我們就能知道彭谁,這個類肯定和 Http 有關吸奴。loadData.fetcher.loadData(helper.getPriority(), this) 的具體實現(xiàn)方法也跟著找到了
@Override
public void loadData(Priority priority, DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
final InputStream result;
try {
result = loadDataWithRedirects(glideUrl.toURL(), 0 /*redirects*/, null /*lastUrl*/,
glideUrl.getHeaders());
}
……
callback.onDataReady(result);
}
private InputStream loadDataWithRedirects(……) throws IOException {
……
if (statusCode / 100 == 2) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (statusCode / 100 == 3) {
……
處理重定向
……
}
……
異常處理
……
}
private InputStream getStreamForSuccessfulRequest(HttpURLConnection urlConnection)
throws IOException {
……
stream = urlConnection.getInputStream();
}
return stream;
}
以上這些代碼不做解釋了,就是發(fā)起網(wǎng)絡請求缠局,接收返回的數(shù)據(jù)流则奥。
loadData() 方法還有一句
callback.onDataReady(result);
這里的 callback 就是 SourceGenerator,所以看 SourceGenerator.onDataReady()
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (……) {
dataToCache = data;
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
如果執(zhí)行成功了會執(zhí)行 cb.reschedule() 或者 cb.onDataFetcherReady() 這里的 cb 是 DecodeJob
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
DataSource dataSource, Key attemptedKey) {
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
TraceCompat.beginSection("DecodeJob.decodeFromRetrievedData");
try {
decodeFromRetrievedData();
} finally {
TraceCompat.endSection();
}
}
}
callback.reschedule(this) 其實就是 EngineJob..reschedule()
public void reschedule(DecodeJob<?> job) {
// Even if the job is cancelled here, it still needs to be scheduled so that it can clean itself
// up.
getActiveSourceExecutor().execute(job);
}
用來再次執(zhí)行 DecodeJob 狭园,會改變 DecodeJob 的 runReason读处。這些任務調度比較復雜,經(jīng)過一些列 debug 得出結果如下
經(jīng)過一些列的 reschedule 如果圖片下面成功會執(zhí)行 decodeFromRetrievedData()
decodeFromRetrievedData
>> notifyEncodeAndRelease
>> notifyComplete
>> callback.onResourceReady
最終調用 EngineJob.onResourceReady()
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
this.resource = resource;
this.dataSource = dataSource;
MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
}
public boolean handleMessage(Message message) {
EngineJob<?> job = (EngineJob<?>) message.obj;
switch (message.what) {
case MSG_COMPLETE:
job.handleResultOnMainThread();
break;
……
}
return true;
}
}
void handleResultOnMainThread() {
……
for (ResourceCallback cb : cbs) {
if (!isInIgnoredCallbacks(cb)) {
engineResource.acquire();
cb.onResourceReady(engineResource, dataSource);
}
}
……
engineResource.release();
release(false /*isRemovedFromQueue*/);
}
handleResultOnMainThread 中的 cb.onResourceReady(engineResource, dataSource) 即通知資源獲取成功唱矛。這里的 cb 即 SingleRequest 和上一部分內容對接上了罚舱。
public <R> LoadStatus load(……) {
……
……
engineJob.addCallback(cb); // 傳入 SingleRequest
engineJob.start(decodeJob);
……
}
總結以上流程如下
備注
Glide 還有很多需要探究的知識點,這篇文章寫不下了绎谦。先寫那么多吧管闷。