因爲以前項目搭建的是 MVP 架構,由RxJava + Glide + OKHttp + Retrofit
等開源框架組合而成,以前也都是停留在使用層面上,沒有深刻的研究,最近打算把它們所有攻下,尚未關注的同窗能夠先關注一波,看完這個系列文章,(不論是面試仍是工做中處理問題)相信你都在知道原理的狀況下,處理問題更加駕輕就熟。java
Android 圖片加載框架 Glide 4.9.0 (一) 從源碼的角度分析 Glide 執行流程android
Android 圖片加載框架 Glide 4.9.0 (二) 從源碼的角度分析 Glide 緩存策略git
從源碼的角度分析 Rxjava2 的基本執行流程、線程切換原理github
從源碼的角度分析 OKHttp3 (一) 同步、異步執行流程面試
從源碼的角度分析 OKHttp3 (二) 攔截器的魅力設計模式
從源碼的角度分析 Retrofit 網絡請求,包含 RxJava + Retrofit + OKhttp 網絡請求執行流程緩存
相信你們在項目上應該都有用過或者瞭解過 Glide 圖片加載框架吧,那麼在用的時候是否是發現 Glide 一行代碼就能對圖片進行下載 -> 緩存 -> 顯示 ,那麼 Glide 內部它究竟是怎麼實現的?下面咱們就來分析下 Glide 執行流程,腦殼裏面先有一個對 Glide 源碼整體執行流程的認識,咱們就從下面最簡單的代碼開始分析:安全
Glide.with(Activity activity).load(String url).into(ImageView imageView);
複製代碼
上面這簡簡單單的一行代碼,內部實際上是極爲的複雜。網絡
ps: 建議閱讀時間爲 30 分鐘,看完我相信你會有收穫的。
在分析 with 源碼以前,先看一下 Glide.with 執行的時序圖,先對執行的流程有一個瞭解,咱們在來分析代碼幹了些什麼?
上面只是 Glide.with(Activity act) 的流程,那麼上面涉及到的這幾個類,他們的職責主要幹什麼的,咱們來看看。
RequestManager
請求管理類,而後綁定一個 Fragment 。流程跟各個角色我們介紹了,如今介紹下代碼具體實現;
調用 with
Glide.with(Activity);
複製代碼
咱們能夠看下 with 這個源碼函數,重載有不少。
@NonNull
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
@NonNull
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
@NonNull
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
/** @deprecated */
@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
複製代碼
其實經常使用的就 Activity,Fragment, Context 這 3 種形式,下面咱們就以 Activity 爲主。
getRetriever(activity)
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
Preconditions.checkNotNull(context, "You cannot start a load on a not yet attached View or a Fragment where getActivity() returns null (which usually occurs when getActivity() is called before the Fragment is attached or after the Fragment is destroyed).");
return get(context).getRequestManagerRetriever();
}
複製代碼
繼續看 get(context)
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
Class var1 = Glide.class;
synchronized(Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
複製代碼
這裏的 Glide get(Context) 是一種雙重檢測單例模式(DCL),保證了多線程下安全,若是對單例模式還不清楚的能夠看我之間寫的 單例設計模式詳解 ,下面咱們看下 checkAndInitializeGlide(context); 它到底作了什麼?
private static void checkAndInitializeGlide(@NonNull Context context) {
if (isInitializing) {
//這裏會拋出初始化異常的信息
} else {
//是否初始化標誌
isInitializing = true;
//開始進行初始化
initializeGlide(context);
isInitializing = false;
}
}
複製代碼
繼續看 initializeGlide(context);
private static void initializeGlide(@NonNull Context context) {
//實例化一個 GlideBuilder 在進行初始化
//GlideBuilder 默認的一些配置信息
initializeGlide(context, new GlideBuilder());
}
複製代碼
繼續跟蹤
private static void initializeGlide(@NonNull Context context, @NonNull GlideBuilder builder) {
//1. 拿到應用級別的上下文,這裏能夠避免內存泄漏,咱們實際開發也能夠經過這種形式拿上下文。
Context applicationContext = context.getApplicationContext();
//2. 這裏拿到 @GlideModule 標識的註解處理器生成的 GeneratedAppGlideModuleImpl、GeneratedAppGlideModuleFactory ...等等。
GeneratedAppGlideModule annotationGeneratedModule = getAnnotationGeneratedGlideModules();
.....
//3. 經過註解生成的代碼拿到 RequestManagerFactory
RequestManagerFactory factory = annotationGeneratedModule != null ? annotationGeneratedModule.getRequestManagerFactory() : null;
//4. 將拿到的工廠添加到 GlideBuilder
builder.setRequestManagerFactory(factory);
....
//5. 這裏經過 Builder 建造者模式,構建出 Glide 實例對象
Glide glide = builder.build(applicationContext);
Iterator var13 = manifestModules.iterator();
//6. 開始註冊組件回調
while(var13.hasNext()) {
GlideModule module = (GlideModule)var13.next();
module.registerComponents(applicationContext, glide, glide.registry);
}
if (annotationGeneratedModule != null) {
annotationGeneratedModule.registerComponents(applicationContext, glide, glide.registry);
}
applicationContext.registerComponentCallbacks(glide);
//將構建出來的 glide 賦值給 Glide 的靜態變量
Glide.glide = glide;
}
複製代碼
經過上面的註釋,相信你們很容易理解,注意看註釋 5 ,這裏知道是經過建造者生成的,那麼具體內部怎麼實現的,咱們來看看。
package com.bumptech.glide;
/** * A builder class for setting default structural classes for Glide to use. */
public final class GlideBuilder {
//管理線程池
private Engine engine;
//對象池(享元模式),這樣作避免重複建立對象,對內存開銷有必定效果
private BitmapPool bitmapPool;
private ArrayPool arrayPool;
//GlideExecutor 線程池
private GlideExecutor sourceExecutor;
private GlideExecutor diskCacheExecutor;
//本地磁盤緩存
private DiskCache.Factory diskCacheFactory;
//內存緩存
private MemorySizeCalculator memorySizeCalculator;
private MemoryCache memoryCache;
private ConnectivityMonitorFactory connectivityMonitorFactory;
private int logLevel = Log.INFO;
private RequestOptions defaultRequestOptions = new RequestOptions();
@Nullable
private RequestManagerFactory requestManagerFactory;
private GlideExecutor animationExecutor;
private boolean isActiveResourceRetentionAllowed;
@Nullable
private List<RequestListener<Object>> defaultRequestListeners;
private boolean isLoggingRequestOriginsEnabled;
//都是一些配置信息,用到了 開閉原則。
....
//開始構建
@NonNull
Glide build(@NonNull Context context) {
//實例化一個網絡請求的線程池
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
//實例化一個本地磁盤緩存的線程池
if (diskCacheExecutor == null) {
diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();
}
//實例化一個加載圖片動畫的一個線程池
if (animationExecutor == null) {
animationExecutor = GlideExecutor.newAnimationExecutor();
}
//實例化一個對圖片加載到內存的一個計算
if (memorySizeCalculator == null) {
memorySizeCalculator = new MemorySizeCalculator.Builder(context).build();
}
//實例化一個默認網絡鏈接監控的工廠
if (connectivityMonitorFactory == null) {
connectivityMonitorFactory = new DefaultConnectivityMonitorFactory();
}
//實例化一個 Bitmap 對象池
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
//若是池子裏還有可用的,直接加入 最近最少使用的 LruBitmap 容器裏
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
//若是池子已經滿了,那麼就裝在 BitmapPoolAdapter
bitmapPool = new BitmapPoolAdapter();
}
}
//實例化一個數組對象池
if (arrayPool == null) {
arrayPool = new LruArrayPool(memorySizeCalculator.getArrayPoolSizeInBytes());
}
//資源內存緩存
if (memoryCache == null) {
memoryCache = new LruResourceCache(memorySizeCalculator.getMemoryCacheSize());
}
//磁盤緩存的工廠
if (diskCacheFactory == null) {
diskCacheFactory = new InternalCacheDiskCacheFactory(context);
}
//構建執行緩存策略跟線程池的引擎
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
GlideExecutor.newAnimationExecutor(),
isActiveResourceRetentionAllowed);
}
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
//實例化一個 RequestManagerRetriever 請求管理類
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
//實例化 Glide 的地方
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptions.lock(),
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled);
}
}
複製代碼
經過上面代碼跟註釋咱們可知,這裏 builder 主要構建線程池、複用池、緩存策略、執行 Engine ,最後構建 Glide 實例,咱們看看 Glide 怎麼實例化的,主要看對應的構造函數就好了。
Glide(
@NonNull Context context,
@NonNull Engine engine,
@NonNull MemoryCache memoryCache,
@NonNull BitmapPool bitmapPool,
@NonNull ArrayPool arrayPool,
@NonNull RequestManagerRetriever requestManagerRetriever,
@NonNull ConnectivityMonitorFactory connectivityMonitorFactory,
int logLevel,
@NonNull RequestOptions defaultRequestOptions,
@NonNull Map<Class<?>, TransitionOptions<?, ?>> defaultTransitionOptions,
@NonNull List<RequestListener<Object>> defaultRequestListeners,
boolean isLoggingRequestOriginsEnabled) {
//將 Builder 構建的線程池,對象池,緩存池保存到 Glide 中
this.engine = engine;
this.bitmapPool = bitmapPool;
this.arrayPool = arrayPool;
this.memoryCache = memoryCache;
this.requestManagerRetriever = requestManagerRetriever;
this.connectivityMonitorFactory = connectivityMonitorFactory;
//拿到 Glide 對應須要的編解碼
DecodeFormat decodeFormat = defaultRequestOptions.getOptions().get(Downsampler.DECODE_FORMAT);
bitmapPreFiller = new BitmapPreFiller(memoryCache, bitmapPool, decodeFormat);
final Resources resources = context.getResources();
registry = new Registry();
registry.register(new DefaultImageHeaderParser());
//忽略一些配置信息
...
//用於顯示對應圖片的工廠
ImageViewTargetFactory imageViewTargetFactory = new ImageViewTargetFactory();
//構建一個 Glide 專屬的 上下文
glideContext =
new GlideContext(
context,
arrayPool,
registry,
imageViewTargetFactory,
defaultRequestOptions,
defaultTransitionOptions,
defaultRequestListeners,
engine,
isLoggingRequestOriginsEnabled,
logLevel);
}
複製代碼
這裏的 GlideContext 實際上是 Context 級別的上下文。
public class GlideContext extends ContextWrapper{
...
}
複製代碼
到這裏咱們已經知道了 緩存策略、Glide、GlideContext 怎麼構建出來的了,下面咱們看怎麼拿到 請求管理類 RequestManager
RequestManager getRetriever(activity).get(activity);
這裏的 get 也有不少重載的函數,咱們就看 Activity 參數的重載。
public class RequestManagerRetriever implements Handler.Callback {
@NonNull
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
//若是在主線程中而且不爲 Application 級別的 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) {
//一直到查找 BaseContext
return get(((ContextWrapper) context).getBaseContext());
}
}
//若是不在主線程中或爲 Application 就直接執行
return getApplicationManager(context);
}
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
....
}
@NonNull
public RequestManager get(@NonNull Fragment fragment) {
....
}
//經過 Activity 拿到 RequestManager
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
//判斷當前是否在子線程中請求任務
if (Util.isOnBackgroundThread()) {
//經過 Application 級別的 Context 加載
return get(activity.getApplicationContext());
} else {
//檢查 Activity 是否已經銷燬
assertNotDestroyed(activity);
//拿到當前 Activity 的 FragmentManager
android.app.FragmentManager fm = activity.getFragmentManager();
//主要是生成一個 Fragment 而後綁定一個請求管理 RequestManager
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
}
複製代碼
下面咱們看下 fragmentGet 函數實現
private RequestManager fragmentGet(@NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) {
//1. 在當前的 Acitivty 添加一個 Fragment 用於管理請求的生命週期
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
//拿到當前請求的管理類
RequestManager requestManager = current.getRequestManager();
//若是不存在,則建立一個請求管理者保持在當前管理生命週期的 Fragment 中,至關於 2 者進行綁定,避免內存泄漏。
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
//返回當前請求的管理者
return requestManager;
}
複製代碼
經過上面的代碼可知,這裏用於 Fragment 管理請求的生命週期,那麼咱們具體來看看 Fragment 怎麼添加到 Activity 中。
private RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) {
//經過 TAG 拿到已經實例化過的 Fragment ,至關於若是同一個 Activity Glide.with..屢次,那麼就沒有必要建立多個。
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
//若是在當前 Activity 中沒有拿到管理請求生命週期的 Fragment ,那麼就從緩存中看有沒有
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
//若是緩存也沒有得,就直接實例化一個 Fragment
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
//若是已經有執行的請求就開始
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
//添加到 Map 緩存中
pendingRequestManagerFragments.put(fm, current);
//經過當前 Activity 的 FragmentManager 開始提交添加一個 Fragment 容器
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//添加到 FragmentManager 成功,發送清理緩存。
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
複製代碼
最後就到了 把請求管理類綁定到 Fragment 中。
private RequestManager fragmentGet(@NonNull Context context, @NonNull android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) {
...
//若是不存在,則建立一個請求管理者保持在當前管理生命週期的 Fragment 中,至關於 2 者進行綁定,避免內存泄漏。
if (requestManager == null) {
//拿到單例 Glide
Glide glide = Glide.get(context);
//構建請求管理,current.getGlideLifecycle(),就是 ActivityFragmentLifecycle 後面咱們會講到這個類
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
//將構建出來的請求管理綁定在 Fragment 中。
current.setRequestManager(requestManager);
}
//返回當前請求的管理者
return requestManager;
}
複製代碼
看下怎麼構建請求管理類的
private static final RequestManagerFactory DEFAULT_FACTORY = new RequestManagerFactory() {
@NonNull
@Override
public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode requestManagerTreeNode, @NonNull Context context) {
//實例化
return new RequestManager(glide, lifecycle, requestManagerTreeNode, context);
}
};
複製代碼
public RequestManager( @NonNull Glide glide, @NonNull Lifecycle lifecycle, @NonNull RequestManagerTreeNode treeNode, @NonNull Context context) {
this(
glide,
lifecycle,
treeNode,
new RequestTracker(),
glide.getConnectivityMonitorFactory(),
context);
}
// Our usage is safe here.
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.context = context;
connectivityMonitor =
factory.build(
context.getApplicationContext(),
new RequestManagerConnectivityListener(requestTracker));
//這裏只要是添加生命週期監聽,Fragment 傳遞過來的
if (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
//添加網絡變化的監聽
lifecycle.addListener(connectivityMonitor);
defaultRequestListeners =
new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
glide.registerRequestManager(this);
}
複製代碼
到這裏請求管理類 RequestManager + Fragment 已經綁定成功了,聲明週期監聽也設置了。
那他們相互是怎麼保證生命週期的傳遞勒,咱們主要看 Fragment 生命週期方法
//這裏爲何監控 Fragment 的生命週期勒,其實你們應該也知道 Fragment 是依附在 Activity 的 Activity 的生命週期在 Fragment 中都有,因此監聽 Fragment 就好了。
public class RequestManagerFragment extends Fragment {
//至關於生命週期回調
private final ActivityFragmentLifecycle lifecycle;
....
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
}
...
}
複製代碼
這裏的 lifecycle 是什麼,咱們在深刻看看去
class ActivityFragmentLifecycle implements Lifecycle {
private final Set<LifecycleListener> lifecycleListeners =
Collections.newSetFromMap(new WeakHashMap<LifecycleListener, Boolean>());
private boolean isStarted;
private boolean isDestroyed;
@Override
public void addListener(@NonNull LifecycleListener listener) {
lifecycleListeners.add(listener);
if (isDestroyed) {
listener.onDestroy();
} else if (isStarted) {
listener.onStart();
} else {
listener.onStop();
}
}
@Override
public void removeListener(@NonNull LifecycleListener listener) {
lifecycleListeners.remove(listener);
}
void onStart() {
isStarted = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
void onStop() {
isStarted = false;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStop();
}
}
void onDestroy() {
isDestroyed = true;
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onDestroy();
}
}
}
複製代碼
這裏知道了吧,它實現的是 Glide 中的 Lifecycle 生命週期接口,註冊是在剛剛咱們講解 RequestManagerFactory 工廠中實例化的 RequestManager 而後在構造函數中添加了生命週期回調監聽,具體來看下。
public class RequestManager implements LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
...
@Override
public synchronized void onStart() {
resumeRequests();
targetTracker.onStart();
}
@Override
public synchronized void onStop() {
pauseRequests();
targetTracker.onStop();
}
@Override
public synchronized void onDestroy() {
targetTracker.onDestroy();
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
...
}
複製代碼
這 3 處回調就是 Fragment 傳遞過來的,用於實時監聽請求的狀態。
with 小總結:
根據 with 源碼分析,咱們知道,Glide.with(Activity) 主要作了 線程池 + 緩存 + 請求管理與生命週期綁定+其它配置初始化的構建,內部的代碼實際上是很龐大的,到處都是設計模式,若是還有對設計模式不瞭解的建議翻看下我以前寫的設計模式文章。到這裏 Glide.with 咱們已經分析完了,下面咱們看 load 函數主要作了什麼?
下面咱們就來以 load(String url) 網絡圖片地址爲例來說解 load 過程。
Glide.with(this).load("https://ss0.bdstatic.com/70cFuHSh_Q1YnxGkpoWK1HF6hhy/it/u=3638429004,1717840478&fm=26&gp=0.jpg")
複製代碼
仍是老規矩,先上一個時序圖。
load 函數加載相對於比較簡單。咱們看下具體代碼實現
public class RequestManager implements LifecycleListener, ModelTypes<RequestBuilder<Drawable>> {
.....
public RequestBuilder<Drawable> load(@Nullable String string) {
//這裏調用 Drawable 圖片加載請求器爲其加載
return asDrawable().load(string);
}
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
@NonNull
@CheckResult
@Override
public RequestBuilder<Drawable> load(@Nullable File file) {
return asDrawable().load(file);
}
public <ResourceType> RequestBuilder<ResourceType> as( @NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
}
複製代碼
能夠看到 load 也有不少重載的函數,不得不說是真的很強大啊,只要給一個圖片資源那麼就能給你加載出來。
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>> implements Cloneable, ModelTypes<RequestBuilder<TranscodeType>> {
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
// 描述加載的數據源-這裏能夠看作是咱們剛剛傳遞進來的 http://xxxx.png
@Nullable private Object model;
// 描述這個請求是否已經添加了加載的數據源
private boolean isModelSet;
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
}
複製代碼
好的, 到這裏 RequestBuilder 就構建好了, 接下來就等待執行這個請求了, 咱們看看它的 RequestBuilder 的 into 方法。
終於等到 into 主角了,你們是否是都等不急了,那麼如今咱們就一塊兒跟着 into 走一趟吧,仍是老規矩,先上一個時序圖。
跟了 2 小時 into 時序圖終於畫完了,若是以爲不清晰,能夠下載原版 涉及到的類和回調確實太多了,下面就跟着我一塊兒看下代碼具體執行流程。
Glide.with(activity).load(http://xxxx.png).into(imageView);
複製代碼
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
// 根據 ImageView 佈局中的 scaleType 來重構 requestOptions
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
//若是在 xml ImageView 節點中 沒有設置 scaleType 那麼默認在構造函數中進行了初始化爲 mScaleType = ScaleType.FIT_CENTER;
switch (view.getScaleType()) {
.....
case FIT_CENTER:
case FIT_START:
case FIT_END:
//這裏用到了克隆(原型設計模式),選擇一個 居中合適 顯示的方案
requestOptions = requestOptions.clone().optionalFitCenter();
break;
....
}
}
//調用 into 重載函數,建立一個 ViewTarget
return into(
//調用 buildImageViewTarget 構建一個 ImageView 類型的 Target(Bitmap/Drawable)
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
複製代碼
根據上面代碼和註釋可知:
咱們先來看下 glideContext.buildImageViewTarget 是怎麼構建出來 ImageViewTarget 的
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
//調用 工廠模式 根據 transcodeClass 生成出一個對應的 ImageViewTarget
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
複製代碼
public class ImageViewTargetFactory {
@NonNull
@SuppressWarnings("unchecked")
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view, @NonNull Class<Z> clazz) {
//若是目標的編碼類型屬於 Bitmap 那麼就建立一個 Bitmap 類型的 ImageViewTarget
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
////若是目標的編碼類型屬於 Drawable 那麼就建立一個 Drawable 類型的 ImageViewTarget
} else if (Drawable.class.isAssignableFrom(clazz)) {
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view);
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
}
複製代碼
上面 生產 Target 的時候注意一下,只要調用了 asBitmap
纔會執行生產 BitmapImageViewTarget ,因此這裏咱們關注 Drawable 類型就好了,咱們就先簡單看看這個 target 內部怎麼實現的,由於最後會講到這個,先讓你們有個印象。
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
public DrawableImageViewTarget(ImageView view) {
super(view);
}
@SuppressWarnings({"unused", "deprecation"})
@Deprecated
public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitForLayout);
}
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
}
複製代碼
從上面代碼能夠知道 DrawableImageViewTarget 繼承的是 ImageViewTarget 重寫的 setResource 函數,實現了顯示 Drawable 圖片的邏輯,好了,這裏先有個印象就行,最後會講到怎麼調用的。繼續 into 重載。
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) {
Preconditions.checkNotNull(target);
//這裏的 isModelSet 是在 load 的時候賦值爲 true 的,因此不會拋異常
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//爲這個 http://xxx.png 生成一個 Glide request 請求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//至關於拿到上一個請求
Request previous = target.getRequest();
//下面的幾行說明是否與上一個請求衝突,通常不用管 直接看下面 else 判斷
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
//清理掉目標請求管理
requestManager.clear(target);
//從新爲目標設置一個 Glide request 請求
target.setRequest(request);
//最後是調用 RequestManager 的 track 來執行目標的 Glide request 請求
requestManager.track(target, request);
return target;
}
複製代碼
上面有 2 點比較重要:
咱們就簡單的來看下怎麼構建的 Request
private Request buildRequest( Target<TranscodeType> target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> requestOptions, Executor callbackExecutor) {
return buildRequestRecursive(
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
}
複製代碼
繼續跟蹤
private Request obtainRequest( Target<TranscodeType> target, RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> requestOptions, RequestCoordinator requestCoordinator, TransitionOptions<?, ? super TranscodeType> transitionOptions, Priority priority, int overrideWidth, int overrideHeight, Executor callbackExecutor) {
return SingleRequest.obtain(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
複製代碼
最後咱們發現是 SingleRequest.obtain
來爲咱們構建的 Request 請求對象,開始只是初始化一些配置屬性,下面咱們就來找begin
開始的地方, 先來看下 track
函數執行。
//這裏對當前 class 加了一個同步鎖避免線程引發的安全性
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
//添加一個目標任務
targetTracker.track(target);
//執行 Glide request
requestTracker.runRequest(request);
}
複製代碼
public void runRequest(@NonNull Request request) {
//添加一個請求
requests.add(request);
//是否暫停
if (!isPaused) {
//沒有暫停,開始調用 Request begin 執行
request.begin();
} else {
//若是調用了 暫停,清理請求
request.clear();
pendingRequests.add(request);
}
}
複製代碼
上面的邏輯是先爲 requests
添加一個請求,看看是不是中止狀態,若是不是就調用 request.begin();
執行。
這裏的 Request
是一個接口,經過以前咱們講到 buildRequest
函數可知 Request
的實現類是 SingleRequest
咱們就直接看它的 begin
函數.
@Override
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
//檢查外部調用的尺寸是否有效
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
//失敗的回調
int logLevel = getFallbackDrawable() == null ? Log.WARN : Log.DEBUG;
onLoadFailed(new GlideException("Received null model"), logLevel);
return;
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
if (status == Status.COMPLETE) {
//表示資源準備好了
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
status = Status.WAITING_FOR_SIZE;
//這裏表示大小已經準備好了
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//開始
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
//這裏是剛剛開始執行的回調,至關於顯示開始的進度
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished run method in " + LogTime.getElapsedMillis(startTime));
}
}
複製代碼
咱們直接看 onSizeReady
public synchronized void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
....//都是一些初始化狀態,配置屬性,咱們不用管。
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,
callbackExecutor);
}
複製代碼
繼續跟蹤下去
public synchronized <R> LoadStatus load( GlideContext glideContext, Object model, Key signature, int width, int height, Class<?> resourceClass, Class<R> transcodeClass, Priority priority, DiskCacheStrategy diskCacheStrategy, Map<Class<?>, Transformation<?>> transformations, boolean isTransformationRequired, boolean isScaleOnlyOrNoTransform, Options options, boolean isMemoryCacheable, boolean useUnlimitedSourceExecutorPool, boolean useAnimationPool, boolean onlyRetrieveFromCache, ResourceCallback cb, Executor callbackExecutor) {
//拿到緩存或者請求的 key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//根據 key 拿到活動緩存中的資源
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
//若是 ActiveResources 活動緩存中有就回調出去
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
return null;
}
//嘗試從 LruResourceCache 中找尋這個資源
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
//若是內存緩存 Lru 中資源存在回調出去
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
return null;
}
//------------- 走到這裏說明活動緩存 跟內存 緩存都沒有找到 -----------
//根據 Key 看看緩存中是否正在執行
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
//若是正在執行,把數據回調出去
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
// -------------- 走到這裏說明是一個新的任務 ---------------
// -------------- 構建新的請求任務 ---------------
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
//把當前須要執行的 key 添加進緩存
jobs.put(key, engineJob);
//執行任務的回調
engineJob.addCallback(cb, callbackExecutor);
//開始執行。
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
複製代碼
經過 engine.load
這個函數裏面的邏輯,咱們能夠總結幾點:
下面咱們就來看下 engineJob.start
具體執行邏輯:
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
//拿到 Glide 執行的線程池
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
//開始執行
executor.execute(decodeJob);
}
複製代碼
經過 DecodeJob
源碼得知,它是實現的 Runnable
接口,這裏 GlideExecutor 線程池開始執行,就會啓動 DecodeJob 的 run 函數,咱們跟蹤 run 的實現。
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob<?>>, Poolable {
//線程執行調用 run
@Override
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
//是否取消了當前請求
if (isCancelled) {
notifyFailed();
return;
}
//執行
runWrapped();
} catch (CallbackException e) {
.....//一些錯誤回調
}
}
複製代碼
跟蹤 runWrapped
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//獲取資源狀態
stage = getNextStage(Stage.INITIALIZE);
//根據當前資源狀態,獲取資源執行器
currentGenerator = getNextGenerator();
//執行
runGenerators();
break;
...
}
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
//若是外部調用配置了資源緩存策略,那麼返回 Stage.RESOURCE_CACHE
//不然繼續調用 Stage.RESOURCE_CACHE 執行。
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
//若是外部配置了源數據緩存,那麼返回 Stage.DATA_CACHE
//不然繼續調用 getNextStage(Stage.DATA_CACHE)
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
//若是隻能從緩存中獲取數據,則直接返回 FINISHED,不然,返回SOURCE。
//意思就是一個新的資源
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
複製代碼
經過上面代碼能夠知道,咱們在找資源的執行器,這裏因爲咱們沒有在外部配置緩存策略因此,直接從源數據加載,看下面代碼。
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);
}
}
複製代碼
//這裏咱們知道,返回的是 SourceGenerator
源數據執行器。繼續下面代碼執行
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//判斷是否取消,是否開始
//調用 DataFetcherGenerator.startNext() 判斷是不是屬於開始執行的任務
while (!isCancelled && currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) {
....
}
複製代碼
這裏咱們先看 currentGenerator.startNext()
這句代碼,DataFetcherGenerator
是一個抽象類,那麼這裏執行的實現類是哪個,能夠參考下面一張表格;
資源狀態 | 描述 | 資源執行器 |
---|---|---|
Stage.RESOURCE_CACHE | 從磁盤中獲取緩存的資源數據。 | ResourceCacheGenerator |
Stage.DATA_CACHE | 從磁盤中獲取緩存的源數據。 | DataCacheGenerator |
Stage.SOURCE | 一次新的請求任務 | SourceGenerator |
由於這裏咱們沒有配置緩存,那麼直接看 SourceGenerator
@Override
public boolean startNext() {
...
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
//獲取一個 ModelLoad 加載器
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
//使用加載器中的 fetcher 根據優先級加載數據
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
複製代碼
這裏咱們就看 helper.getLoadData()
獲取的是一個什麼樣的加載器,咱們能夠先猜一下,由於沒有配置任何緩存,因此能夠猜獲得是 http 請求了,那麼是否是猜想的那樣的,咱們一塊兒來驗證下。
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
//從 Glide 註冊的 Model 來獲取加載器(註冊是在 Glide 初始化的時候經過 registry
// .append()添加的)
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
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;
}
複製代碼
首先拿到一個加載器的容器,加載器是在 Glide 初始化的時候 經過 Registry.append()
添加的,這裏由於咱們以網絡連接舉例的。因此,ModelLoad 的實現類是 HttpGlideUrlLoader
加載器,咱們看下它的具體實現
@Override
public LoadData<InputStream> buildLoadData(@NonNull GlideUrl model, int width, int height, @NonNull Options options) {
GlideUrl url = model;
if (modelCache != null) {
url = modelCache.get(model, 0, 0);
if (url == null) {
modelCache.put(model, 0, 0, model);
url = model;
}
}
int timeout = options.get(TIMEOUT);
return new LoadData<>(url, new HttpUrlFetcher(url, timeout));
}
複製代碼
這裏看到是返回的一個HttpUrlFetcher
給加載器。加載器咱們拿到了,如今開始加載,返回到剛剛的源碼,請看下面:
class DataCacheGenerator implements DataFetcherGenerator, DataFetcher.DataCallback<Object> {
//挑重要代碼
@Override
public boolean startNext() {
....
while (!started && hasNextModelLoader()) {
ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
loadData =
modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
helper.getOptions());
if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
started = true;
//經過拿到的加載器,開始加載數據
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
}
複製代碼
由於剛剛咱們知道了這裏拿到的加載器是HttpUrlFetcher
因此咱們直接看它的 loadData 實現
@Override
public void loadData(@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
//http 請求,返回一個 InputStream 輸入流
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
//將 InputStream 以回調形式回調出去
callback.onDataReady(result);
} catch (IOException e) {
callback.onLoadFailed(e);
} finally {
...
}
}
複製代碼
咱們繼續看 loadDataWithRedirects
這個函數是怎麼生成的一個 InputStream
private InputStream loadDataWithRedirects(URL url, int redirects, URL lastUrl, Map<String, String> headers) throws IOException {
if (redirects >= MAXIMUM_REDIRECTS) {
throw new HttpException("Too many (> " + MAXIMUM_REDIRECTS + ") redirects!");
} else {
try {
if (lastUrl != null && url.toURI().equals(lastUrl.toURI())) {
throw new HttpException("In re-direct loop");
}
} catch (URISyntaxException e) {
// Do nothing, this is best effort.
}
}
urlConnection = connectionFactory.build(url);
for (Map.Entry<String, String> headerEntry : headers.entrySet()) {
urlConnection.addRequestProperty(headerEntry.getKey(), headerEntry.getValue());
}
urlConnection.setConnectTimeout(timeout);
urlConnection.setReadTimeout(timeout);
urlConnection.setUseCaches(false);
urlConnection.setDoInput(true);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.connect();
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
}
...//拋的異常咱們暫時先無論
}
複製代碼
是否是發現了新大陸,終於到了咱們熟悉的 Http 請求了,這裏是 HttpURLConnection 做爲 Glide 底層成網絡請求的。請求成功以後直接返回的是一個輸入流,最後會經過 onDataReady
回調到 DecodeJob onDataFetcherReady 函數中。咱們跟下回調
首先回調到 SourceGenerator
@Override
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
複製代碼
這裏會有 else 由於咱們沒有配置緩存,繼續回調。
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob<?>>, Poolable {
...
@Override
public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey; //當前返回數據的 key
this.currentData = data; //返回的數據
this.currentFetcher = fetcher; //返回的數據執行器,這裏能夠理解爲 HttpUrlFetcher
this.currentDataSource = dataSource; //數據來源 url
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
//解析返回回來的數據
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
...
}
//解析返回的數據
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
// 調用 decodeFrom 解析 數據;HttpUrlFetcher , InputStream , currentDataSource
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
//解析完成後,通知下去
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
複製代碼
繼續跟 decodeFromData 看看怎麼解析成 Resource 的
private <Data> Resource<R> decodeFromData(DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
...
Resource<R> result = decodeFromFetcher(data, dataSource);
....
return result;
} finally {
fetcher.cleanup();
}
}
@SuppressWarnings("unchecked")
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource) throws GlideException {
//獲取當前數據類的解析器 LoadPath
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
//經過 LoadPath 解析器來解析數據
return runLoadPath(data, dataSource, path);
}
private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path) throws GlideException {
Options options = getOptionsWithHardwareConfig(dataSource);
//由於這裏返回的是一個 InputStream 因此 這裏拿到的是 InputStreamRewinder
DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
try {
//將解析資源的任務轉移到 Load.path 方法中
return path.load(
rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
} finally {
rewinder.cleanup();
}
}
複製代碼
上面代碼看到,爲了解析數據首先構建一個 LoadPath, 而後建立一個 InputStreamRewinder 類型的 DataRewinder, 最終將數據解析的操做放到了 LoadPath.load 方法中 ,接下來看下 LoadPath.load 方法的具體邏輯操做:
public Resource<Transcode> load(DataRewinder<Data> rewinder, @NonNull Options options, int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback) throws GlideException {
try {
return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
} finally {
listPool.release(throwables);
}
}
private Resource<Transcode> loadWithExceptionList(DataRewinder<Data> rewinder, @NonNull Options options, int width, int height, DecodePath.DecodeCallback<ResourceType> decodeCallback, List<Throwable> exceptions) throws GlideException {
Resource<Transcode> result = null;
//遍歷內部存儲的 DecodePath 集合,經過他們來解析數據
for (int i = 0, size = decodePaths.size(); i < size; i++) {
DecodePath<Data, ResourceType, Transcode> path = decodePaths.get(i);
try {
//這裏纔是真正解析數據的地方
result = path.decode(rewinder, width, height, options, decodeCallback);
} catch (GlideException e) {
...
}
...
return result;
}
複製代碼
跟 path.decode
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
//調用 decodeResourec 將數據解析成中間資源
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
//解析完數據回調出去
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
//轉換資源爲目標資源
return transcoder.transcode(transformed, options);
}
複製代碼
接着看 decodeResource 怎麼解析成中間資源的
@NonNull
private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options) throws GlideException {
...
try {
return decodeResourceWithList(rewinder, width, height, options, exceptions);
} finally {
...
}
}
@NonNull
private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException {
Resource<ResourceType> result = null;
//noinspection ForLoopReplaceableByForEach to improve perf
for (int i = 0, size = decoders.size(); i < size; i++) {
ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
try {
DataType data = rewinder.rewindAndGet();
if (decoder.handles(data, options)) {
data = rewinder.rewindAndGet();
// 調用 ResourceDecoder.decode 解析數據
result = decoder.decode(data, width, height, options);
}
} catch (IOException | RuntimeException | OutOfMemoryError e) {
...
}
return result;
}
複製代碼
能夠看到數據解析的任務最終是經過 DecodePath 來執行的, 它內部有三個操做
deResource 將源數據解析成資源
調用 DecodeCallback.onResourceDecoded 處理資源
調用 ResourceTranscoder.transcode 將資源轉爲目標資源
經過上面的 decoder.decode 源碼可知,它是一個接口,因爲咱們這裏的源數據是 InputStream,因此,它的實現類是 StreamBitmapDecoder ,咱們就來看下 它內部的解碼過程
@Override
public Resource<Bitmap> decode(@NonNull InputStream source, int width, int height, @NonNull Options options) throws IOException {
// Use to fix the mark limit to avoid allocating buffers that fit entire images.
final RecyclableBufferedInputStream bufferedStream;
final boolean ownsBufferedStream;
....
try {
// 根據請求配置來對數據進行採樣壓縮,獲取一個 Resource<Bitmap>
return downsampler.decode(invalidatingStream, width, height, options, callbacks);
} finally {
....
}
}
複製代碼
具體怎麼採樣壓縮,咱們先暫時不用關注具體實現,如今拿到了一個 Bitmap 數據,咱們須要經過回調出去,請看下面代碼
public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
//1. 調用 decodeResourec 將數據解析成中間資源 Bitmap
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
//2. 解析完數據回調出去
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
//3. 轉換資源爲目標資源 Bitmap to Drawable
return transcoder.transcode(transformed, options);
}
複製代碼
只看第二註釋裏面回調,最後會回調到 DecodeJob
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob<?>>, Poolable {
...
@Override
public Resource<Z> onResourceDecoded(@NonNull Resource<Z> decoded) {
return DecodeJob.this.onResourceDecoded(dataSource, decoded);
}
...
}
複製代碼
繼續跟
@Synthetic
@NonNull
<Z> Resource<Z> onResourceDecoded(DataSource dataSource, @NonNull Resource<Z> decoded) {
@SuppressWarnings("unchecked")
//獲取資源類型
Class<Z> resourceSubClass = (Class<Z>) decoded.get().getClass();
Transformation<Z> appliedTransformation = null;
Resource<Z> transformed = decoded;
//若是不是從磁盤資源中獲取須要進行 transform 操做
if (dataSource != DataSource.RESOURCE_DISK_CACHE) {
appliedTransformation = decodeHelper.getTransformation(resourceSubClass);
transformed = appliedTransformation.transform(glideContext, decoded, width, height);
}
...
//構建數據編碼的策略
final EncodeStrategy encodeStrategy;
final ResourceEncoder<Z> encoder;
if (decodeHelper.isResourceEncoderAvailable(transformed)) {
encoder = decodeHelper.getResultEncoder(transformed);
encodeStrategy = encoder.getEncodeStrategy(options);
} else {
encoder = null;
encodeStrategy = EncodeStrategy.NONE;
}
//根據編碼策略,構建緩存 Key
Resource<Z> result = transformed;
boolean isFromAlternateCacheKey = !decodeHelper.isSourceKey(currentSourceKey);
if (diskCacheStrategy.isResourceCacheable(isFromAlternateCacheKey, dataSource,
encodeStrategy)) {
if (encoder == null) {
throw new Registry.NoResultEncoderAvailableException(transformed.get().getClass());
}
final Key key;
switch (encodeStrategy) {
case SOURCE:
//源數據 key
key = new DataCacheKey(currentSourceKey, signature);
break;
。。。
}
//初始化編碼管理者,用於提交內存緩存
LockedResource<Z> lockedResult = LockedResource.obtain(transformed);
deferredEncodeManager.init(key, encoder, lockedResult);
result = lockedResult;
}
//返回轉換後的 Bitmap
return result;
}
複製代碼
能夠看到 onResourceDecoded 中, 主要是對中間資源作了以下的操做
最後就是將 Bitmap 轉換成 Drawable 了操做了 ,請看下面代碼
public class DecodePath<DataType, ResourceType, Transcode> {
。。。
Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
//1. 調用 decodeResourec 將數據解析成中間資源 Bitmap
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
//2. 解析完數據回調出去
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
//3. 轉換資源爲目標資源 Bitmap to Drawable
return transcoder.transcode(transformed, options);
}
。。。
}
複製代碼
只看第三步,經過源碼可知,ResourceTranscoder 是一個接口,又由於解析完的數據是 Bitmap 因此它的實現類是 BitmapDrawableTranscoder ,最後看下它的 transcode 具體實現
public class BitmapDrawableTranscoder implements ResourceTranscoder<Bitmap, BitmapDrawable> {
@Nullable
@Override
public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode, @NonNull Options options) {
return LazyBitmapDrawableResource.obtain(resources, toTranscode);
}
}
複製代碼
具體咱們看下 LazyBitmapDrawableResource.obtain
public final class LazyBitmapDrawableResource implements Resource<BitmapDrawable>, Initializable {
private final Resources resources;
private final Resource<Bitmap> bitmapResource;
@Deprecated
public static LazyBitmapDrawableResource obtain(Context context, Bitmap bitmap) {
return
(LazyBitmapDrawableResource)
obtain(
context.getResources(),
BitmapResource.obtain(bitmap, Glide.get(context).getBitmapPool()));
}
@Deprecated
public static LazyBitmapDrawableResource obtain(Resources resources, BitmapPool bitmapPool, Bitmap bitmap) {
return
(LazyBitmapDrawableResource) obtain(resources, BitmapResource.obtain(bitmap, bitmapPool));
}
@Nullable
public static Resource<BitmapDrawable> obtain( @NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
if (bitmapResource == null) {
return null;
}
return new LazyBitmapDrawableResource(resources, bitmapResource);
}
private LazyBitmapDrawableResource(@NonNull Resources resources, @NonNull Resource<Bitmap> bitmapResource) {
this.resources = Preconditions.checkNotNull(resources);
this.bitmapResource = Preconditions.checkNotNull(bitmapResource);
}
@NonNull
@Override
public Class<BitmapDrawable> getResourceClass() {
return BitmapDrawable.class;
}
// Get 方法反回了一個 BitmapDrawable 對象
@NonNull
@Override
public BitmapDrawable get() {
return new BitmapDrawable(resources, bitmapResource.get());
}
@Override
public int getSize() {
return bitmapResource.getSize();
}
@Override
public void recycle() {
bitmapResource.recycle();
}
@Override
public void initialize() {
if (bitmapResource instanceof Initializable) {
((Initializable) bitmapResource).initialize();
}
}
}
複製代碼
轉化也完成了 ,將咱們解析到的 bitmap 存放到 LazyBitmapDrawableResource 內部, 而後外界經過 get 方法就能夠獲取到一個 BitmapDrawable 的對象了。
解析完就到了展現數據了,請看下面代碼:
class DecodeJob<R> implements DataFetcherGenerator.FetcherReadyCallback, Runnable, Comparable<DecodeJob<?>>, Poolable {
//解析返回的數據
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
//1. 調用 decodeFrom 解析 數據;HttpUrlFetcher , InputStream , currentDataSource
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
//2. 解析完成後,通知下去
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
複製代碼
註釋 1 解析完了數據,如今執行 notifyEncodeAndRelease
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
...
//通知調用層數據已經裝備好了
notifyComplete(result, dataSource);
stage = Stage.ENCODE;
try {
//這裏就是將資源磁盤緩存
if (deferredEncodeManager.hasResourceToEncode()) {
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
...
}
//完成
onEncodeComplete();
}
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
// 在 DecodeJob 的構建中, 咱們知道這個 Callback 是 EngineJob
callback.onResourceReady(resource, dataSource);
}
複製代碼
能夠看到 DecodeJob.decodeFromRetrievedData 中主要作了幾個操做
咱們直接看 EngineJob 的 onResourceReady 回調函數
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
@Synthetic
void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource<?> localResource;
synchronized (this) {
stateVerifier.throwIfRecycled();
if (isCancelled) {
resource.recycle();
release();
return;
} else if (cbs.isEmpty()) {
...
}
engineResource = engineResourceFactory.build(resource, isCacheable);
hasResource = true;
copy = cbs.copy();
incrementPendingCallbacks(copy.size() + 1);
localKey = key;
localResource = engineResource;
}
//回調上層 Engine 任務完成了
listener.onEngineJobComplete(this, localKey, localResource);
//遍歷資源回調給 ImageViewTarget
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
複製代碼
經過上面 EngineJob 的 onResourceReady 回調函數 主要作了 2 件事兒
咱們看下 listener.onEngineJobComplete 具體實現
@SuppressWarnings("unchecked")
@Override
public synchronized void onEngineJobComplete( EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
if (resource != null) {
resource.setResourceListener(key, this);
//收到下游返回回來的資源,添加到活動緩存中
if (resource.isCacheable()) {
activeResources.activate(key, resource);
}
}
jobs.removeIfCurrent(key, engineJob);
}
複製代碼
最後通知 ImageViewTarget ,咱們看下具體操做:
//遍歷資源回調給 ImageViewTarget
for (final ResourceCallbackAndExecutor entry : copy) {
entry.executor.execute(new CallResourceReady(entry.cb));
}
複製代碼
private class CallResourceReady implements Runnable {
private final ResourceCallback cb;
CallResourceReady(ResourceCallback cb) {
this.cb = cb;
}
@Override
public void run() {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
...
//返回準備好的資源
callCallbackOnResourceReady(cb);
removeCallback(cb);
}
decrementPendingCallbacks();
}
}
}
複製代碼
經過代碼能夠看到 CallResourceReady 實現 Runnable 他們,當 entry.executor.execute 線程池執行的時候就會調用 run ,最後咱們繼續跟 callCallbackOnResourceReady
@Synthetic
synchronized void callCallbackOnResourceReady(ResourceCallback cb) {
try {
//回調給 SingleRequest
cb.onResourceReady(engineResource, dataSource);
} catch (Throwable t) {
throw new CallbackException(t);
}
}
複製代碼
跟下 SingleRequest onResourceReady 回調實現
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
loadStatus = null;
....
Object received = resource.get();
if (received == null || !transcodeClass.isAssignableFrom(received.getClass())) {
releaseResource(resource);
...
onLoadFailed(exception);
return;
}
if (!canSetResource()) {
releaseResource(resource);
status = Status.COMPLETE;
return;
}
//當資源準備好的時候
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
...
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
//回調給目標 ImageViewTarget 資源準備好了
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
//加載成功
notifyLoadSuccess();
}
複製代碼
這一步主要把準備好的資源回調給顯示層,看下面代碼
public abstract class ImageViewTarget<Z> extends ViewTarget<ImageView, Z> implements Transition.ViewAdapter {
...
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
protected abstract void setResource(@Nullable Z resource);
...
}
private void setResourceInternal(@Nullable Z resource) {
//調用 setResource 函數,將資源顯示出來
setResource(resource);
...
}
複製代碼
在最開始構建的時候,咱們知道只有調用 asBitmap 的時候實現類是 BitmapImageViewTarget
,在這裏的測試,並無調用這個函數,因此它的實現類是 DrawableImageViewTarget
,具體看下它內部實現:
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
public DrawableImageViewTarget(ImageView view) {
super(view);
}
// Public API.
@SuppressWarnings({"unused", "deprecation"})
@Deprecated
public DrawableImageViewTarget(ImageView view, boolean waitForLayout) {
super(view, waitForLayout);
}
@Override
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
}
複製代碼
這裏看到抽象類中調用了 setResource ,子類實現並調用了 view.setImageDrawable(resource); 圖片如今算是真正的顯示出來了。到了這裏 Glide.with(activity).load(http://xxx.png).into(imageView)
這一個流程算是講完了。下面咱們就來爲這整個流程作一個總結吧。
經過這 Glide.with(activity).load(http://xxx.png).into(imageView)
一簡短的代碼,整個 Glide 圖片加載顯示的流程咱們已經熟悉了,還有看源碼不能一行一行的去理解它內部具體實現,咱們只要找準一個點,好比 with 那麼咱們只關注 with 的具體實現,其它什麼也不用管。下面就爲 Glide 整個流程簡單說一下吧:
在閱讀的過程當中,若是對文章有疑問或者描述錯誤的地方,但願你的指出。
感謝你的閱讀,謝謝!