glide調用方法比較簡單如下,這是一個最簡單的例子,後續流程分析就按照這個例子來:
Glide.with(this).load("http://u5.mm-img.mmarket.com/rs/res2/marketing_activities/1513240903060.png"
1.Glide的基本加載流程
1.1幾個重點類的解釋
Glide:glide圖片加載的入口類,裏面維護着它自己的唯一實例對象glide。
RequestManagerRetriever:這個類最主要的用處就是創建一個隱藏的RequestManagerFragment,用來感知宿主Activity的聲明週期變化,主要用來創建RequestManager並且保證對於同一個context來說只會創建一個RequestManager對象。
RequestManager:負責管理所有的Target對象額Request對象,並且實現了生命週期LifecycleListener接口,並且在構造方法中和宿主Activity的生命週期lifecycle進行了綁定,跟隨宿主生命週期變化而變化。其load方法會構建一個RequestBuilder對象,可以鏈式的設置參數供下一步使用。
RequestBuilder:內部包含了大量的請求參數,最主要的就是RequestOptions(請求參數相關)和TransitonOptions(加載完成動畫相關),其中into方法會創建Request對象和Target對象觸發加載請求。
RequestOptions:大量的請求參數,包括佔位符,緩存控制,加載完成之後的動畫等等。
Target:資源加載的目標接口,這個接口定義了資源加載的生命週期方法,比較常見的實現類是DrawableImageViewTarget,典型的生命週期流程:onLoadStarted -> onResourceReady或onLoadFailed -> onLoadCleared。
Request:Request負責真正的加載流程,一般Request和Target是一一對應的,典型的有SingleRequest。
LifecycleListener:定義了三個生命週期方法接口,onStart/onStop/onDestroy。
ModelTypes:定義了load方法的所有重載方式。
1.2基本加載流程
Glide#with:這一步最主要的就是獲取一個RequestManagerRetriever對象
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
Glide#getRetriever:
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
// Context could be null for other reasons (ie the user passes in null), but in practice it will
// only occur due to errors with the Fragment lifecycle.
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 Glide.get(context).getRequestManagerRetriever();
}
Glide#get:構建一個Glide單例對象
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
Glide#getRequestManagerRetriever:這裏比較簡單,獲取RequestManagerRetriever對象,在Glide初始化時被賦值。
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
RequestManagerRetriever#get:RequestManagerRetriever#get方法重載比較多,選取其中一個分析即可。
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
RequestManagerRetriever#fragmentGet:這個方法構建了一個RequestManagerFragment對象,它就是一個Fragment對象,裏面綁定了一些Lifecycle的方法,作用就是通過監聽它的生命週期變化而達到監聽到宿主Activity生命週期的目的。
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
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;
}
RequestManagerRetriever#getRequestManagerFragment:這個方法比較常規
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
GeneratedRequestManagerFactory#build:這個方法主要實現了RequestManager的構建過程。
final class GeneratedRequestManagerFactory implements RequestManagerRetriever.RequestManagerFactory {
@Override
@NonNull
public RequestManager build(@NonNull Glide glide, @NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode treeNode, @NonNull Context context) {
return new GlideRequests(glide, lifecycle, treeNode, context);
}
}
RequestManager#load:
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
RequestManager#as:
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
RequestBuilder#load:
public RequestBuilder<TranscodeType> load(@Nullable Bitmap bitmap) {
return loadGeneric(bitmap)
.apply(diskCacheStrategyOf(DiskCacheStrategy.NONE));
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
RequestBuilder#into:
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// Clone in this method so that if we use this RequestBuilder to load into a View and then
// into a different target, we don't retain the transformation applied based on the previous
// View's scale type.
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions = requestOptions.clone().optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions = requestOptions.clone().optionalFitCenter();
break;
case FIT_XY:
requestOptions = requestOptions.clone().optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
return into(
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
requestOptions,
Executors.mainThreadExecutor());
}
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
public <Z> ViewTarget<ImageView, Z> buildTarget(@NonNull ImageView view,
@NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view);
} 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)");
}
}
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
request.recycle();
// If the request is completed, beginning again will ensure the result is re-delivered,
// triggering RequestListeners and Targets. If the request is failed, beginning again will
// restart the request, giving it another chance to complete. If the request is already
// running, we can let it continue running without interruption.
if (!Preconditions.checkNotNull(previous).isRunning()) {
// Use the previous request rather than the new one to allow for optimizations like skipping
// setting placeholders, tracking and un-tracking Targets, and obtaining View dimensions
// that are done in the individual Request.
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
RequestBuilder#buildRequest:先分析buildRequest源碼,下一步直接分析mainRequest的構建過程即可
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 buildRequestRecursive(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
// Build the ErrorRequestCoordinator first if necessary so we can update parentCoordinator.
ErrorRequestCoordinator errorRequestCoordinator = null;
if (errorBuilder != null) {
errorRequestCoordinator = new ErrorRequestCoordinator(parentCoordinator);
parentCoordinator = errorRequestCoordinator;
}
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
if (errorRequestCoordinator == null) {
return mainRequest;
}
int errorOverrideWidth = errorBuilder.getOverrideWidth();
int errorOverrideHeight = errorBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !errorBuilder.isValidOverride()) {
errorOverrideWidth = requestOptions.getOverrideWidth();
errorOverrideHeight = requestOptions.getOverrideHeight();
}
Request errorRequest =
errorBuilder.buildRequestRecursive(
target,
targetListener,
errorRequestCoordinator,
errorBuilder.transitionOptions,
errorBuilder.getPriority(),
errorOverrideWidth,
errorOverrideHeight,
errorBuilder,
callbackExecutor);
errorRequestCoordinator.setRequests(mainRequest, errorRequest);
return errorRequestCoordinator;
}
RequestBuilder.buildThumbnailRequestRecursive:這個方法比較長,但是隻需要關注最後一個else的邏輯也就是obtainRequest方法即可
private Request buildThumbnailRequestRecursive(
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
if (thumbnailBuilder != null) {
// Recursive case: contains a potentially recursive thumbnail request builder.
if (isThumbnailBuilt) {
throw new IllegalStateException("You cannot use a request as both the main request and a "
+ "thumbnail, consider using clone() on the request(s) passed to thumbnail()");
}
TransitionOptions<?, ? super TranscodeType> thumbTransitionOptions =
thumbnailBuilder.transitionOptions;
// Apply our transition by default to thumbnail requests but avoid overriding custom options
// that may have been applied on the thumbnail request explicitly.
if (thumbnailBuilder.isDefaultTransitionOptionsSet) {
thumbTransitionOptions = transitionOptions;
}
Priority thumbPriority = thumbnailBuilder.isPrioritySet()
? thumbnailBuilder.getPriority() : getThumbnailPriority(priority);
int thumbOverrideWidth = thumbnailBuilder.getOverrideWidth();
int thumbOverrideHeight = thumbnailBuilder.getOverrideHeight();
if (Util.isValidDimensions(overrideWidth, overrideHeight)
&& !thumbnailBuilder.isValidOverride()) {
thumbOverrideWidth = requestOptions.getOverrideWidth();
thumbOverrideHeight = requestOptions.getOverrideHeight();
}
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(
target,
targetListener,
coordinator,
thumbTransitionOptions,
thumbPriority,
thumbOverrideWidth,
thumbOverrideHeight,
thumbnailBuilder,
callbackExecutor);
isThumbnailBuilt = false;
coordinator.setRequests(fullRequest, thumbRequest);
return coordinator;
} else if (thumbSizeMultiplier != null) {
// Base case: thumbnail multiplier generates a thumbnail request, but cannot recurse.
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
Request fullRequest =
obtainRequest(
target,
targetListener,
requestOptions,
coordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
BaseRequestOptions<?> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(
target,
targetListener,
thumbnailOptions,
coordinator,
transitionOptions,
getThumbnailPriority(priority),
overrideWidth,
overrideHeight,
callbackExecutor);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
// Base case: no thumbnail.
return obtainRequest(
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
RequestBuilder.obtainRequest:可以看到,先是從對象池裏面去取,有則共享,減少new對象的成本。然後調用init方法,進行一些參數設置
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);
}
public static <R> SingleRequest<R> obtain(
Context context,
GlideContext glideContext,
Object model,
Class<R> transcodeClass,
BaseRequestOptions<?> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target<R> target,
RequestListener<R> targetListener,
@Nullable List<RequestListener<R>> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory<? super R> animationFactory,
Executor callbackExecutor) {
@SuppressWarnings("unchecked") SingleRequest<R> request =
(SingleRequest<R>) POOL.acquire();
if (request == null) {
request = new SingleRequest<>();
}
request.init(
context,
glideContext,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
engine,
animationFactory,
callbackExecutor);
return request;
}
RequestBuilder.into:再回到RequestBuilder.into,這裏的target實現類是DrawableImageViewTarget,獲取此時是否有正在進行的Request請求,如果有,則進行邏輯判斷,決定是否需要開啓一個新的,還是複用之前的。顯然,我們這裏previous肯定是不存在的。因此需要將當前請求去執行,這裏RequestManager先是清除掉這個traget。
private <Y extends Target<TranscodeType>> Y into(
@NonNull Y target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> options,
Executor callbackExecutor) {
//省去buildRequest的代碼
requestManager.clear(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
target.setRequest(request):將Request和View做了一個綁定的關係,保存在View的tag之中
public void setRequest(@Nullable Request request) {
setTag(request);
}
private void setTag(@Nullable Object tag) {
if (tagId == null) {
isTagUsedAtLeastOnce = true;
view.setTag(tag);
} else {
view.setTag(tagId, tag);
}
}
RequestManager#track:TargetTracker和RequestTracker分別是對target和request做了一個管理,TargetTracker類中更加簡單,有點類似一個擴展的List結構,也就是保存了由當前RequestManager在處理的所有Target的集合,而RequestTracker則是所有Request的集合。
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
RequestTracker#runRequest:分爲兩種情況,isPaused變量標識界面是否處於onStop狀態,如果此時還可見,則直接調用request#begin方法執行,否則是加入到pendingRequests中,這裏pendingRequests的作用僅僅是爲了保證Request不被Gc,因爲requests是一個WeakHashMap,如果不使用pendingRequests強引用緩存,那麼這個請求就有可能被回收掉,這裏是做了這樣一個處理,就能保證這些request不被系統回收掉,同時在requests也一定存在。
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
Request#begin:就以SingleRequest#begin爲例,model此時就是我們傳的那個url,如果爲空,則直接load失敗,然後是一些狀態的檢查和一些回調方法等,接下來判斷size,如果是有效的,則觸發去真正的請求,否則則是設置一個回調,等待view佈局有size之後,再來觸發請求,真正的請求其實就在onSizeReady中被得到執行。
public synchronized void begin() {
assertNotCallingCallbacks();
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
// Only log at more verbose log levels if the user has set a fallback drawable, because
// fallback Drawables indicate the user expects null models occasionally.
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 we're restarted after we're complete (usually via something like a notifyDataSetChanged
// that starts an identical request into the same Target or View), we can simply use the
// resource and size we retrieved the last time around and skip obtaining a new size, starting a
// new load etc. This does mean that users who want to restart a load because they expect that
// the view size has changed will need to explicitly clear the View or Target before starting
// the new load.
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
// Restarts for requests that are neither complete nor running can be treated as new requests
// and can run again from the beginning.
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));
}
}
SingleRequest#onSizeReady:這個方法中,首先檢查狀態是不是在等待size,如果不是,則表明size已經有了,下面則是更新狀態到Status.RUNNING,進而去調用Engine根據參數,這裏麪包含了所有的參數信息,緩存,圖片顯示等等,然後去開始真正請求,網絡、內存、磁盤緩存等等。其實這裏面真正加載資源是在engine.load方法進行的,後面會做詳細分析。
public synchronized void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
if (status != Status.WAITING_FOR_SIZE) {
return;
}
status = Status.RUNNING;
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
if (IS_VERBOSE_LOGGABLE) {
logV("finished setup for calling load in " + LogTime.getElapsedMillis(startTime));
}
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);
// This is a hack that's only useful for testing right now where loads complete synchronously
// even though under any executor running on any thread but the main thread, the load would
// have completed asynchronously.
if (status != Status.RUNNING) {
loadStatus = null;
}
if (IS_VERBOSE_LOGGABLE) {
logV("finished onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
}
Target#onLoadStarted:就以ImageViewTarget爲例來分析,這個方法的實現很簡單,就是爲view提前設置一些狀態,比如placeholder信息等等,然後等待Engine後續的加載完成。
public void onLoadStarted(@Nullable Drawable placeholder) {
super.onLoadStarted(placeholder);
setResourceInternal(null);
setDrawable(placeholder);
}
2.Engine加載資源過程
2.1幾個關鍵類解釋
Key:一個接口,唯一標識加載資源數據的鍵值(包括原始數據和緩存數據)。
EngineKey:實現了key接口,內存緩存鍵值。
Resource:資源接口,常見的實現有DrawableResource、BitmapResource、NonOwnedBitmapResource、BytesResource、SimpleResource、EngineResource、LockedResource
MemoryCache:內存緩存接口,常見的實現類有LruResourceCache使用LRU的內存緩存。
DiskCache:磁盤緩存接口,常見的實現類有DiskLruCache基於LRU算法的磁盤緩存
DiskLruCacheWrapper:glide默認的磁盤緩存實現,其內部使用了DiskLruCache,基於LRU算法
ActiveResources:存放已經被request請求的資源,廣義上說是內存緩存的一種,其實是在內存緩存的基礎之上再做了一層緩存處理。
ResourceRecycler:回收Resource的輔助類
EngineJob:真正的進行資源加載並在加載完成時通知回調來管理加載的類
DecodeJob:從緩存數據或者原始數據解碼資源,並進行轉換的類
Jobs:緩存EngineJob的管理類,內部存放了key和engineJob的map對象。
2.2加載資源流程
2.2.1Engine#load
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) {
long startTime = VERBOSE_IS_LOGGABLE ? LogTime.getLogTime() : 0;
//分析#1
//構建一個engineey,下面對engineKey的構造輸入參數做下解析:
//model:此時是圖片url
//signature: 簽名?沒仔細的研究,一般情況下默認實現是EmptySignature。
//width/height:加載的尺寸
//transformations:是一個Map<Class<?>, Transformation<?>>鍵值對,常見的配對是:
//Bitmap.class -> FitCenter
//Drawable.class -> DrawableTransformation
//BitmapDrawable.class -> DrawableTransformation
//GifDrawable.class -> GifDrawableTransformation
//resourceClass: 此時爲Object.class
//transcodeClass: 指定了需要返回的Resource類型
//options:Options類也是一個實現了Key的接口
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//分析#2
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return null;
}
//分析#3
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return null;
}
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);
jobs.put(key, engineJob);
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
2.2.2Engine#loadFromActiveResources
private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
synchronized EngineResource<?> get(Key key) {
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
EngineResource<?> active = activeRef.get();
if (active == null) {
cleanupActiveReference(activeRef);
}
return active;
}
這段代碼比較簡單,如果isMemoryCacheable可用就直接到activeResources中去查找,activeResources是怎麼保存的呢?activeEngineResources是一個Map<Key, ResourceWeakReference>對象。
2.2.3Engine#loadFromCache
private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
if (!isMemoryCacheable) {
return null;
}
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
activeResources.activate(key, cached);
}
return cached;
}
很簡單只是對isMemoryCacheable的簡單判斷,接着看getEngineResourceFromCache
2.2.4Enging#getEngineResourceFromCache
private EngineResource<?> getEngineResourceFromCache(Key key) {
Resource<?> cached = cache.remove(key);
final EngineResource<?> result;
if (cached == null) {
result = null;
} else if (cached instanceof EngineResource) {
// Save an object allocation if we've cached an EngineResource (the typical case).
result = (EngineResource<?>) cached;
} else {
result = new EngineResource<>(
cached, /*isMemoryCacheable=*/ true, /*isRecyclable=*/ true, key, /*listener=*/ this);
}
return result;
}
cach的具體實現就是LruCache,內部維護了一個LinkedHashMap<Key, Resource<?> cache對象,很顯然如果是第一次加載的話這裏返回null。
2.2.5Enging#load
public <R> LoadStatus load(...{
...
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
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);
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
接着繼續返回到load方法,如果cache返回null了就繼續在jobs中尋找是否存在一個EngineJob,如果存在就複用該EngineJob否則new一個執行start方法。
3.資源加載核心過程EngineJob和DecodeJob
3.1DecodeJob的執行過程
3.1.1 EngineJob#start
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
GlideExecutor executor = decodeJob.willDecodeFromCache()
? diskCacheExecutor
: getActiveSourceExecutor();
executor.execute(decodeJob);
}
很簡單直接看DecodeJob#run方法。
3.1.2 DecodeJob#run
public void run() {
// This should be much more fine grained, but since Java's thread pool implementation silently
// swallows all otherwise fatal exceptions, this will at least make it obvious to developers
// that something is failing.
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
// Methods in the try statement can invalidate currentFetcher, so set a local variable here to
// ensure that the fetcher is cleaned up either way.
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
runWrapped();
} catch (CallbackException e) {
// If a callback not controlled by Glide throws an exception, we should avoid the Glide
// specific debug logic below.
throw e;
} catch (Throwable t) {
// Catch Throwable and not Exception to handle OOMs. Throwables are swallowed by our
// usage of .submit() in GlideExecutor so we're not silently hiding crashes by doing this. We
// are however ensuring that our callbacks are always notified when a load fails. Without this
// notification, uncaught throwables never notify the corresponding callbacks, which can cause
// loads to silently hang forever, a case that's especially bad for users using Futures on
// background threads.
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "DecodeJob threw unexpectedly"
+ ", isCancelled: " + isCancelled
+ ", stage: " + stage, t);
}
// When we're encoding we've already notified our callback and it isn't safe to do so again.
if (stage != Stage.ENCODE) {
throwables.add(t);
notifyFailed();
}
if (!isCancelled) {
throw t;
}
throw t;
} finally {
// Keeping track of the fetcher here and calling cleanup is excessively paranoid, we call
// close in all cases anyway.
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
關鍵方法runWapped,執行邏輯如果出現異常jiuhui清理和重置DecodeJob裏面的一些資源。
3.1.3 DecodeJon#runWapped
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);
}
}
private Stage getNextStage(Stage current) {
switch (current) {
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE : getNextStage(Stage.RESOURCE_CACHE);
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE : getNextStage(Stage.DATA_CACHE);
case DATA_CACHE:
// Skip loading from source if the user opted to only retrieve the resource from cache.
return onlyRetrieveFromCache ? Stage.FINISHED : Stage.SOURCE;
case SOURCE:
case FINISHED:
return Stage.FINISHED;
default:
throw new IllegalArgumentException("Unrecognized stage: " + current);
}
}
runWrapped中主要是根據runReason獲取一個Stage狀態對象,第一次加載我們傳入的應該是INITIALIZE。接着看getNextStage的邏輯,diskCacheStrategy的值一般也是默認值DiskCacheStrategy.AUTOMATIC則decodeCachedResource()返回true,因此stage賦值爲Stage.RESOURCE_CACHE。接着看getNextGenerator的邏輯:
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);
}
}
創建一個DataFetcherGenerator對象,getNextGenerator方法的實現很簡單,就是根據stage的信息,返回相應的對象,這裏我們的stage爲Stage.RESOURCE_CACHE,因此此時currentGenerator就是一個ResourceCacheGenerator對象。再接着,在runWrapped方法中,調用了runGenerators,繼續運行。
3.1.4 DecodeJob#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循環裏的邏輯,條件:!isCancelled && currentGenerator != null && !(isStarted = currentGenerator.startNext())
1.檢查isCancelled狀態,一旦isCancelled爲true或者isStarted爲true,表明任務已經啓動,整個循環就會結束
2.stage狀態爲完成或者被取消並且任務沒有啓動,則直接notifyFailed
3.currentGenerator#startNext表示是否成功啓動了DataFetcher
DecodeJob的run方法,會依次從ResourceCacheGenerator->DataCacheGenerator->SourceGenerator這樣一個鏈執行,只要其中一個的startNext方法返回爲true,則不再尋找下一個Generator。下面重點看下startNex的邏輯,首先看ResourceCacheGenerator的startnext邏輯
3.1.5 ResourceCacheGenerator#startNext
public boolean startNext() {
List<Key> sourceIds = helper.getCacheKeys();
if (sourceIds.isEmpty()) {
return false;
}
List<Class<?>> resourceClasses = helper.getRegisteredResourceClasses();
if (resourceClasses.isEmpty()) {
if (File.class.equals(helper.getTranscodeClass())) {
return false;
}
throw new IllegalStateException(
"Failed to find any load path from " + helper.getModelClass() + " to "
+ helper.getTranscodeClass());
}
while (modelLoaders == null || !hasNextModelLoader()) {
resourceClassIndex++;
if (resourceClassIndex >= resourceClasses.size()) {
sourceIdIndex++;
if (sourceIdIndex >= sourceIds.size()) {
return false;
}
resourceClassIndex = 0;
}
Key sourceId = sourceIds.get(sourceIdIndex);
Class<?> resourceClass = resourceClasses.get(resourceClassIndex);
Transformation<?> transformation = helper.getTransformation(resourceClass);
// PMD.AvoidInstantiatingObjectsInLoops Each iteration is comparatively expensive anyway,
// we only run until the first one succeeds, the loop runs for only a limited
// number of iterations on the order of 10-20 in the worst case.
currentKey =
new ResourceCacheKey(// NOPMD AvoidInstantiatingObjectsInLoops
helper.getArrayPool(),
sourceId,
helper.getSignature(),
helper.getWidth(),
helper.getHeight(),
transformation,
resourceClass,
helper.getOptions());
cacheFile = helper.getDiskCache().get(currentKey);
if (cacheFile != null) {
sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
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;
}
首先通過decodeHelper拿到的sourceIds就是[GlideUrl,ObjectKey],然後獲取resourceClass信息也就是glide所支持的資源類信息大致是[GifDrawable,Bitmap,BitmapDrawable]這些內容。下面是重點邏輯進入一個while循環:
1。由resourceClasses和sourceIds組成的一個正交關係,迭代每一組。
2.迭代開始前,若modelLoaders爲空或者,while內部先檢查是否已經全部迭代完成
3.對每一組,獲取相應的緩存Key對象,根據緩存key去diskcache中查找緩存文件,查找成功,則通過getModelLoaders獲取當前的modelLoaders信息,繼續執行循環。這個循環的主要工作就是找到modelLoaders信息,如果沒有找到startNext就直接返回false了交給下一個generator處理,找到的話就進入該方法的下一個while循環。這個循環邏輯比較簡單:遍歷modelLoaders,只要有一個對應的fetcher能夠處理,則startNext返回true,表明此時這個generator已經能夠處理本次請求,所以也不會再交給其他的generator對應的fetcher去處理了。
3.1.6 DataCacheGenerator#startNext
如果上一個generator沒有處理的話就進入DataCacheGenerator#startNext來了。
public boolean startNext() {
while (modelLoaders == null || !hasNextModelLoader()) {
sourceIdIndex++;
if (sourceIdIndex >= cacheKeys.size()) {
return false;
}
Key sourceId = cacheKeys.get(sourceIdIndex);
// PMD.AvoidInstantiatingObjectsInLoops The loop iterates a limited number of times
// and the actions it performs are much more expensive than a single allocation.
@SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
cacheFile = helper.getDiskCache().get(originalKey);
if (cacheFile != null) {
this.sourceKey = sourceId;
modelLoaders = helper.getModelLoaders(cacheFile);
modelLoaderIndex = 0;
}
}
loadData = null;
boolean started = false;
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;
}
DataCacheGenerator#startNext和ResourceCacheGenerator的startNext方法幾乎一模一樣,接着看SourceGenerator#startNext。
3.1.7 SourceGenerator#startNext
public boolean startNext() {
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
loadData.fetcher.loadData(helper.getPriority(), this);
}
}
return started;
}
這個方法的主要邏輯還是while循環,最主要會調用MultFetcher的loadData方法去請求數據,可以看到loadData的第二個參數callback回調。失敗了層層回調也就結束了,成功會調用SourceGenerator#onDataReady。
3.1.8 SourceGenerator#onDataReady
public void onDataReady(Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
// We might be being called back on someone else's thread. Before doing anything, we should
// reschedule to get back onto Glide's thread.
cb.reschedule();
} else {
cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
loadData.fetcher.getDataSource(), originalKey);
}
}
這裏分爲兩部分:1.如果數據可以緩存的話cb.reschedule-會調用SourceGenerator的startNex緩存數據。2.如果不能緩存的話會回調到上一層處理,SourceGenerator的上一層爲DecodeJob,
3.2EngineJob與DecodeJob代碼詳細加載過程
glide加載過程就是由EngineJob觸發DecodeJob,DecodeJob中會有ResourceCacheGenerator->DataCacheGenerator->SourceGenerator對應的ModelLoaders與ModelFetchers依次處理,如果是SourceGenerator則還會更新緩存。在DecodeJob中獲取到數據之後,則會層層上報,由Fetcher->Generator->DecodeJob->EngineJob->SingleRequest->Target這樣一個序列回調
4.Glide的緩存架構
4.1內存緩存和磁盤緩存
4.1.1內存緩存
glide的內存緩存包括ActiveResources緩存和MemoryCache,MemoryCache我們很好理解,就是Resouce在內存中的緩存。主要說一下ActiveResources,ActiveResources緩存和MemoryCache是同時存在的。ActiveResources緩存存放的是所有未被clear的Request請求到的Resource,這部分Resource會存放至ActiveResources緩存中,當Request被clear的時候,會把這部分在ActiveResources緩存中的Resource移動至MemoryCache中去,只有MemoryCache中能夠命中,則這部分resource又會從MemoryCache移至ActiveResources緩存中去。其實相當於是對內存緩存再次做了一層,能夠有效的提高訪問速度。
4.1.2磁盤緩存
磁盤緩存比較簡單,其中也分爲ResourceCacheKey與DataCacheKey,一個是已經decode過的可以之間供Target給到View去渲染的,另一個是還未decode過的,緩存的是源數據。磁盤緩存的保存是在第一次請求網絡成功時候,會刷新磁盤緩存,此時處理的是源數據,至於是否會緩存decode過後的數據,取決於DiskCacheStrategy的策略。