重學Android——Glide4.x源碼分析(2)java
先來講下世面上經常使用的三種圖片加載框架Picasso,Glide,Frescoandroid
Picasso與Glide相比:git
Frescogithub
Glide能作Picasso能作的全部事情,更快,能處理大型圖片流,通常Glide是首選;Fresco當使用圖片很是多的應用時,它的優點很是明顯api
implementation ("com.github.bumptech.glide:glide:4.9.0") {
exclude group: "com.android.support"
}
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
複製代碼
Glide.with(this)
.load("http://pic37.nipic.com/20140113/8800276_184927469000_2.png")
.into(imageView);
<uses-permission android:name="android.permission.INTERNET" />
複製代碼
須要注意的是,咱們在Android9.0以上使用,用的http請求的話,須要在AndroidMainfest中緩存
<application
...
android:usesCleartextTraffic="true">
複製代碼
緣由是android9.0之後,默認禁止http請求的。網絡
先看Glide.with()方法app
@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);
}
@SuppressWarnings("deprecation")
@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);
}
複製代碼
能夠看到,with方法有多個重載方法,並且都是先調用了getRetriever
這個方法,那麼咱們先看這個方法的源碼框架
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
...
return Glide.get(context).getRequestManagerRetriever();
}
複製代碼
從源碼看,直接是調用Glide的get()方法,而後再調用getRequestManagerRetriever
ide
先看get方法
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
synchronized (Glide.class) {
if (glide == null) {
checkAndInitializeGlide(context);
}
}
}
return glide;
}
複製代碼
一看原來Glide是單例,只有第一次會實例化,經過Builder模式實例化Glide對象,初始化後調用getRequestManagerRetriever方法來獲得RequestManagerRetriever對象。
那麼問題又回到了getRetriever(xxx).get(xxx);這裏,當getRetriever獲得了RequestManagerRetriever對象,咱們繼續看後面的get方法
//get方法也和with同樣,有多個對應的重載
@NonNull
public RequestManager get(@NonNull Context context) {
if (context == null) {
throw new IllegalArgumentException("You cannot start a load on a null Context");
} else if (Util.isOnMainThread() && !(context instanceof Application)) {
//直接返回ApplicationManager
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());
}
}
//傳入的context爲ApplicationContext
return getApplicationManager(context);
}
//get(Activity/fragement)邏輯都差很少的,這裏只拿getFragmentActivity來說
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
//後臺時,就調用get(context)
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
//前臺可見,建立一個FragmentManager
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
@NonNull
private RequestManager supportFragmentGet( @NonNull Context context, @NonNull FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
//獲取RequestManager
SupportRequestManagerFragment current =
getSupportRequestManagerFragment(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爲空,建立requestManager,並把Lifecycle傳了進去
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
//緩存這個requestManager
current.setRequestManager(requestManager);
}
return requestManager;
}
//建立並添加一個SupportRequestManagerFragment
@NonNull
private SupportRequestManagerFragment getSupportRequestManagerFragment( @NonNull final FragmentManager fm, @Nullable Fragment parentHint, boolean isParentVisible) {
SupportRequestManagerFragment current =
(SupportRequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if (current == null) {
current = pendingSupportRequestManagerFragments.get(fm);
if (current == null) {
current = new SupportRequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingSupportRequestManagerFragments.put(fm, current);
//在這裏,使用fragmentManager添加了一個隱藏的無界面Fragment
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_SUPPORT_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
複製代碼
能夠看到,get方法的重載方法不少,可是核心都是同樣的的,就是返回兩種requestManager,1. ApplicationManager,它的生命週期與應用同步,應用退出,Glide也退出;2. 附加在Fragment之上的requestManager,經過這個fragment,綁定了對應的生命週期,這樣就能夠在Activity銷燬時往上加載了,RxPermission也是這麼設計的。
public class SupportRequestManagerFragment extends Fragment {
private static final String TAG = "SupportRMFragment";
private final ActivityFragmentLifecycle lifecycle;
...
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
registerFragmentWithRoot(getActivity());
} catch (IllegalStateException e) {
// OnAttach can be called after the activity is destroyed, see #497.
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Unable to register fragment with root", e);
}
}
}
@Override
public void onDetach() {
super.onDetach();
parentFragmentHint = null;
unregisterFragmentWithRoot();
}
@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();
}
...
}
複製代碼
能夠看到,SupportRequestManagerFragment就是這麼設計的,注入了一個生命週期監聽器ActivityFragmentLifecycle,並在Fragment的各個生命週期中,調用了對應的方法。
class ActivityFragmentLifecycle implements Lifecycle {
...
@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();
}
}
}
複製代碼
能夠看到,在ActivityFragmentLifecycle會緊接着調用lifecycleListener監聽器,而這個監聽器其實就是RequestManager。
最後,能夠看到,生命週期已與requestManager進行了綁定。
接下來咱們看load方法的源碼
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
複製代碼
先來看前面的asDrawable
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
public <ResourceType> RequestBuilder<ResourceType> as( @NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
複製代碼
其實就至關於new RequestBuilder,那再看load
public RequestBuilder<TranscodeType> load(@Nullable String string) {
return loadGeneric(string);
}
@NonNull
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
複製代碼
能夠看到load方法很是簡單,實際上是建立了RequestBuilder,並把傳遞進來的參數url賦值給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.
//這些都與ImageView的scaleType相關,是轉換邏輯,與咱們關心的代碼流程無關,能夠不用關心
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());
}
複製代碼
分析源碼能夠知道,它的內部調用了into的重載方法
咱們先看裏面的參數方法glideContext.buildImageViewTarget(view, transcodeClass),
@NonNull
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)");
}
}
複製代碼
能夠看到,返回了ViewTarger,還記得上面咱們看到的asDrawable麼,說明是DrawableImageViewTarget,接下來再看外層的into方法
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 request = buildRequest(target, targetListener, options, callbackExecutor);
//獲取targert以前的請求任務(若是有的話)
Request previous = target.getRequest();
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
//新構建的request上一個相等,而且設置了緩存以及沒有執行完成
//釋放新的request
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()) {
//當舊的request沒有在運行。執行它的begin
// 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;
}
// 清除先Target以前的全部任務並釋放資源
requestManager.clear(target);
//把新的request設置給target
target.setRequest(request);
//在這裏執行request,下載圖片任務
requestManager.track(target, request);
return target;
}
private boolean isSkipMemoryCacheWithCompletePreviousRequest( BaseRequestOptions<?> options, Request previous) {
//是否設置緩存以及上一次是否執行完成
return !options.isMemoryCacheable() && previous.isComplete();
}
複製代碼
這裏主要作了兩件事:
再來看requestManager的track方法
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
public void track(@NonNull Target<?> target) {
targets.add(target);
}
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
//當處於前臺可見時,調用request的begin
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
//先不執行request,只把它加入到一個準備隊列
pendingRequests.add(request);
}
}
複製代碼
可的看到,track方法是先將target添加到targetTracker類的targets集合中,而後運行request的begin方法。
到這裏,其實圖片加載網絡資源的流程已經完成了大半了。接下來接着看如何加載資源並顯示到target上的。
咱們直接點request.begin方法去跟蹤源碼,會發現Request只是一個接口,因此咱們要找到它的實現類。
那麼咱們再看上面的建立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 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) {
...
//關鍵代碼
Request mainRequest =
buildThumbnailRequestRecursive(
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
if (errorRequestCoordinator == null) {
return mainRequest;
}
...
//若是有設置錯誤時的處理邏輯
return errorRequestCoordinator;
}
複製代碼
能夠看到,真正的核心代碼在buildThumbnailRequestRecursive方法
//這個方法結構其實很簡單,可是參數太多,因此把參數省略再看
private Request buildThumbnailRequestRecursive( ...) {
//默認的thumbnailBuilder就是空的,除非手動調用RequestBuilder類的thumbnail方法
//不然這個if代碼塊永遠執行不到
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();
}
//縮略圖請求協議器,同時協調原圖與縮略圖的request
ThumbnailRequestCoordinator coordinator = new ThumbnailRequestCoordinator(parentCoordinator);
//原圖請求
Request fullRequest =
obtainRequest(...);
isThumbnailBuilt = true;
// Recursively generate thumbnail requests.
//調用buildRequestRecursive,仍是會調到buildThumbnailRequestRecursive,這是個遞歸方法
//遞歸生成縮略圖請求
Request thumbRequest =
thumbnailBuilder.buildRequestRecursive(...);
isThumbnailBuilt = false;
//把這兩個request包裝到ThumbnailRequestCoordinator中
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(...);
BaseRequestOptions<?> thumbnailOptions =
requestOptions.clone().sizeMultiplier(thumbSizeMultiplier);
Request thumbnailRequest =
obtainRequest(...);
coordinator.setRequests(fullRequest, thumbnailRequest);
return coordinator;
} else {
//只加載原圖
// Base case: no thumbnail.
return obtainRequest(...);
}
}
複製代碼
能夠看到,在buildThumbnailRequestRecursive主要作了有無縮略圖的判斷,而後再進行加載,最後調用了obtainRequest方法
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,//對應load(url),好比一個圖片地址
transcodeClass,
requestOptions,
overrideWidth,//寬
overrideHeight,//高
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),//全局加載引擎
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
複製代碼
這個方法經過SingleReques
類的方法obtain去建立一個Request對象,因此,它就是咱們要找的requst,那麼看它的begin方法
@Override
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;
//若是Target的寬高已經獲取併合法,就開始下一步
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));
}
}
複製代碼
能夠看到,begin方法通過一系列的判斷,當status是RUNNING或者WAITING_FOR_SIZE狀態,而且須要設置佔位圖時,會調用onLoadStarted設置佔位圖,當狀態是COMPLETE時,會執行onResourceReady方法並返回。
@Override
public synchronized void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
loadStatus = null;
...
//判斷是否須要設置資源,若是不須要就直接釋放並設置狀態爲COMPLETE
if (!canSetResource()) {
releaseResource(resource);
// We can't put the status to complete before asking canSetResource().
status = Status.COMPLETE;
return;
}
//執行方法
onResourceReady((Resource<R>) resource, (R) received, dataSource);
}
複製代碼
上面省略了一大段加載失敗的代碼,直接來看onResourceReady的重載方法。
private synchronized void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
// We must call isFirstReadyResource before setting status.
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
...
try {
boolean anyListenerHandledUpdatingTarget = false;
if (requestListeners != null) {
for (RequestListener<R> listener : requestListeners) {
anyListenerHandledUpdatingTarget |=
listener.onResourceReady(result, model, target, dataSource, isFirstResource);
}
}
anyListenerHandledUpdatingTarget |=
targetListener != null
&& targetListener.onResourceReady(result, model, target, dataSource, isFirstResource);
//設置資源及動畫相關的信息
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation =
animationFactory.build(dataSource, isFirstResource);
//這個target有多個,好比DrawableImageViewTarget
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
//最後通知加載成功
notifyLoadSuccess();
}
複製代碼
能夠看到,當狀態爲COMPLETE時,就是把當前result設置到當前的target上,並通知加載成功(作一些加載成功後的清理工做)。
上面是COMPLETE時的狀態,那麼不是這個狀態時呢?會執行到onSizeReady方法
@Override
public synchronized void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
...
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,//對應rul,圖片地址
requestOptions.getSignature(),
this.width,
this.height,
requestOptions.getResourceClass(),//默認是Object.class
transcodeClass,//默認是Drawable.class
priority,
requestOptions.getDiskCacheStrategy(),//緩存策略,默認是AUTOMATIC
requestOptions.getTransformations(),
requestOptions.isTransformationRequired(),
requestOptions.isScaleOnlyOrNoTransform(),
requestOptions.getOptions(),
requestOptions.isMemoryCacheable(),
requestOptions.getUseUnlimitedSourceGeneratorsPool(),
requestOptions.getUseAnimationPool(),
requestOptions.getOnlyRetrieveFromCache(),
this,
callbackExecutor);
}
複製代碼
能夠看到,調用了Engine的load方法,關於加載圖片的加載機制,咱們下一篇再講,今天先就講到這。
這一篇主要分析Glide.with().load().into()的簡單流程
參考
下面是個人公衆號,歡迎你們關注我