基于 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 靜態對象去實現。
逐步分析
Glide.with(……)
Glide.with() 有下面幾種實現方式。
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)
所以的方法實現也是很類似,都是調用同一個方法
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() 方法會根據傳入的 context 對象和當前線程,創建不同的 RequestManager 實例
1. 非 UI 線程,返回 applicationManager 對象,能感知 Application 生命周期。
2. UI 線程,如果 context 是 Activity 、FragmentActivity
則會創建一個能感知對應 Activity 的 RequestManager。
3. UI 線程,如果 Context 是 Fragment、android.support.v4.app.Fragment
則會創建一個能感知對應 Fragment 生命周期 的 RequestManager。
這里反復提到了一個 感知生命 xx 周期
,也是 Glide 的一個特性。
Glide 在加載資源的時候,如果是在 Activity、Fragment 這一類有生命周期的組件上進行。
當 Activity、Fragment 等組件進入不可見,或者已經銷毀的時候,Glide 會停止加載資源。
Application 的生命周期貫穿整個應用,所以 applicationManager 只有在應用程序關閉的時候終止加載。
所以盡量不要在非 UI 線程使用 Glide 加載圖片,盡量使用 Activity、Fragment 等帶有生命周期的組件配合 Glide 使用。
Glide 如何獲得 Activity、Fragment 生命周期回調
在 各種 requestManagerRetriever.get() 方法中如果傳入的是帶有生命周期的組件,并且在 UI 線程,會執行以下幾個方法端
// 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. 創建一個 RequestManagerFragment。
2. 創建一個 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 設計中比較一個巧妙的地方
創建一個透明的 RequestManagerFragment 加入到FragmentManager 之中
通過添加的這個 Fragment 感知 Activity 、Fragment 的生命周期。
在Fragment 源碼學習,從源碼理解 Fragment 生命周期中已經說明,添加到 Activity的 Fragment 會跟隨Activity的生命周期。
Fragment的 childFragment 則會通過 ChildFragmentManager 和 Fragment 保持生命周期一致。
這里說一個細節
剛開始看這段代碼時,看到 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();
}
專業就可以通過 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) 的相關代碼,發現并沒有什么特殊之處。 只是創建了一個 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) 會發現這里返回的是一個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 ,直接執行 request.begin()
2. 如果 GlideRequests 的 Lifecycle 是觀測 Fragment 或者 Activity
isPaused 為true ,不會立即執行 request.begin()
當 Fragment 或者 Activity 顯示到前臺時通過遍歷 requests 數組執行 request.begin()
所以執行網絡請求下載圖片的操作在 request.begin()
之中。
回到 into(ImageView view) 方法的
Request request = buildRequest(target, targetListener, options)
經過層層包裹我們可以找到一下路線,發現最后返回的是 SingleRequest
buildRequest >> buildRequestRecursive >> buildThumbnailRequestRecursive
>> obtainRequest >> SingleRequest
創建 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) 創建一個 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 尺寸發生改變。
流程最終都會執行 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(……) {
……
如果資源已經緩存,直接調用 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 是用來加載網絡資源的,如果資源已經存在,不會重復加載。
先看下 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 從網絡下載圖片的流程更復雜,后面重點講。
Glide 網絡加載圖片
Glide 網絡加載圖片比較負責,找了很久才找到做網絡請求的部分。這里單獨拉出來講。
先回到 load() 方法。
public <R> LoadStatus load(……) {
……
如果資源已經緩存,直接調用 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();
}
……
}
正常情況下會執行
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。
接著執行 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 循環條件里面的 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;
}
這又出現了新的對象 loadData 并且執行 loadData.fetcher.loadData(……)
看起來特別想是加載網絡圖片操作,但是這部分代碼有點不好理解。
loadData 是什么?
fetcher 又是什么?
搞不清池這兩個對象是什么,根本沒法繼續跟進了!!!
尋找 loadData
根據 while 那段代碼判斷 helper.getLoadData() 似乎返回了不止一個 loadData ,所以需要循環遍歷每一個 loadData 找到能執行 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
然后執行 modelLoader.buildLoadData(model, width, height, options) 創建 LoadData 并添加到 List 返回。
于是又引入兩個問題
ModelLoader 是啥玩意?
modelLoader.buildLoadData() 做啥玩意?
啊~~~~~ 好頭疼!!!
繼續跟代碼
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;
}
以上方法似乎還是看不出什么,在這里糾結很久。最后發現在 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 類型的有三個,但是我們是網絡下載圖片所以可以排除第三個。
每一個 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()
再次發現,又代理給了 <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) 的具體實現方法也跟著找到了
@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;
}
以上這些代碼不做解釋了,就是發起網絡請求,接收返回的數據流。
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);
}
}
如果執行成功了會執行 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);
}
用來再次執行 DecodeJob ,會改變 DecodeJob 的 runReason。這些任務調度比較復雜,經過一些列 debug 得出結果如下
經過一些列的 reschedule 如果圖片下面成功會執行 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 還有很多需要探究的知識點,這篇文章寫不下了。先寫那么多吧。