提示:Glide源碼比較多,也比較復(fù)雜,多看幾遍就懂了。加油~~
一般用法:
Glide.with(getContext())
.load(url)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.placeholder(R.drawable.ic_default)
.into(newDrawableImageViewTarget(mAvatarImgView));
}
一 、with方法
1.1 Glide.with()
with()方法是Glide類中的一組靜態(tài)方法,返回RequestManager對象,它有好幾個方法重載,我們來看一下Glide類中所有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.getContext()).get(fragment);
}
1.2 Glide.RequestManagerRetriever()
getRetriever()獲取RequestManagerRetriever。
@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 Glide.get(context).getRequestManagerRetriever();
}
@NonNull
public RequestManagerRetriever getRequestManagerRetriever() {
return requestManagerRetriever;
}
1.3 Glide.get(context):
@NonNull
public static Glide get(@NonNull Context context) {
...
//初始化Glide
checkAndInitializeGlide(context,annotationGeneratedModule);
...
}
return glide;
}
private static void checkAndInitializeGlide(
@NonNull Context context, @Nullable GeneratedAppGlideModule generatedAppGlideModule) {
//glide不能初始化兩次
if (isInitializing) {
throw new IllegalStateException(
"You cannot call Glide.get() in registerComponents(),"
+ " use the provided Glide instance instead");
}
isInitializing = true;
initializeGlide(context, generatedAppGlideModule);
isInitializing = false;
}
private static void initializeGlide(@NonNull Context context,@NonNull GlideBuilder builder,@Nullable GeneratedAppGlideModuleannotationGeneratedModule){
...
//創(chuàng)建RequestManagerRetriever.RequestManagerFactory
RequestManagerRetriever.RequestManagerFactory factory =
annotationGeneratedModule != null
? annotationGeneratedModule.getRequestManagerFactory()
: null;
builder.setRequestManagerFactory(factory);
//這個builder就是GlideBuilder,用來構(gòu)建Glide對象
Glide glide = builder.build(applicationContext);
}
1.4 接著看GlideBuilder類中build方法:
@NonNull
Glide build(@NonNull Context context) {
//sourceExecutor是進(jìn)行網(wǎng)絡(luò)請求的執(zhí)行器
if (sourceExecutor == null) {
sourceExecutor = GlideExecutor.newSourceExecutor();
}
//diskCacheExecutor磁盤緩存執(zhí)行器,后面從磁盤獲取緩存數(shù)據(jù)用到
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();
}
if (bitmapPool == null) {
int size = memorySizeCalculator.getBitmapPoolSize();
if (size > 0) {
bitmapPool = new LruBitmapPool(size);
} else {
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);
}
//構(gòu)建執(zhí)行引擎
if (engine == null) {
engine =
new Engine(
memoryCache,
diskCacheFactory,
diskCacheExecutor,
sourceExecutor,
GlideExecutor.newUnlimitedSourceExecutor(),
animationExecutor,
isActiveResourceRetentionAllowed);
}
if (defaultRequestListeners == null) {
defaultRequestListeners = Collections.emptyList();
} else {
defaultRequestListeners = Collections.unmodifiableList(defaultRequestListeners);
}
//構(gòu)建了一個RequestManagerRetriever對象
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
//構(gòu)建Glide對象,并將上面初始化時創(chuàng)建的各種功能類封裝進(jìn)去
return new Glide(
context,
engine,
memoryCache,
bitmapPool,
arrayPool,
requestManagerRetriever,
connectivityMonitorFactory,
logLevel,
defaultRequestOptionsFactory,
defaultTransitionOptions,
defaultRequestListeners,
isLoggingRequestOriginsEnabled,
isImageDecoderEnabledForBitmaps);
}
以上就是初始化Glide、并構(gòu)建Engine對象、還有各種線程池、各種緩存執(zhí)行器等
1.5 RequestManagerRetriever.get()
接著上面繼續(xù),通過RequestManagerRetriever的get方法獲取RequestManager對象
通過上下文類型分別走不同的get方法.
@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)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrap
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
return getApplicationManager(context);
}
@SuppressWarnings("deprecation")
@NonNull
public RequestManager get(@NonNull Activity activity) {
if (Util.isOnBackgroundThread()) {
//如果是是在子線程執(zhí)行,讓走ApplicationContext的get方法,也就是說生命周期跟application保持一致。else里面先判斷activity是否destroyed
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
//fragmentGet方法里面將glide內(nèi)置的一個不可見的fragment跟當(dāng)前的activity綁定
return fragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
以傳入上下文是Activity為例,繼續(xù)查看是怎么得到RequestManager的,factory就是RequestManagerFactory對象
private RequestManager fragmentGet(
@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
//這個current就是glide自己的fragment,用來綁定生命周期的。
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
Glide glide = Glide.get(context);
requestManager =
// private final RequestManagerFactory factory;
//current.getGlideLifecycle()是glide潛入的frgament的生命周期監(jiān)聽類
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
RequestManagerFactory是一個接口,build方法的參數(shù)里面?zhèn)魅肓薒ifecycle對象。這個Lifecycle是用來監(jiān)聽內(nèi)潛fragment的生命周期的。
public interface RequestManagerFactory {
@NonNull
RequestManager build(
@NonNull Glide glide,
@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode requestManagerTreeNode,
@NonNull Context context);
}
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);
}
};
RequestManagerRetriever類中看似有很多個get()方法的重載,什么Context參數(shù),Activity參數(shù),F(xiàn)ragment參數(shù)等等,實(shí)際上只有兩種情況而已,即傳入Application類型的參數(shù),和傳入非Application類型的參數(shù)。
如果在Glide.with()方法中傳入的是一個Application對象,它自動就是和應(yīng)用程序的生命周期是同步的,如果應(yīng)用程序關(guān)閉的話,Glide的加載也會同時終止。
如果在Glide.with()方法中傳入非Application參數(shù),那就是會向當(dāng)前的Activity當(dāng)中添加一個隱藏的Fragment,這個隱藏的Fragment的生命周期就和當(dāng)前Activity的生命周期綁定了。
如果我們是在非主線程當(dāng)中使用的Glide,那么不管你是傳入的Activity還是Fragment,都會被強(qiáng)制當(dāng)成Application來處理。
界面不可見或者銷毀的時候,通過這樣的方法還能避免Glide持有Activity的實(shí)例而發(fā)生內(nèi)存泄漏問題。
小結(jié):
with()方法傳入當(dāng)前環(huán)境,是為了讓圖片加載保持生命周期同步。并且返回RequestManager對象供load()方法使用。RequestManager能夠用于管理和啟動對Glide的請求。還可以控制生命周期事件智能地停止,啟動和重新啟動請求.
2、load()方法
2.1 RequestManager.load()
因為gilde支持很多圖片來源。所以load方法也有很多重栽方法。
load()方法是在RequestManager里面。
//加載Bitmap
public RequestBuilder<Drawable> load(@Nullable Bitmap bitmap) {
return asDrawable().load(bitmap);
}
//加載Drawable
@Override
public RequestBuilder<Drawable> load(@Nullable Drawable drawable) {
return asDrawable().load(drawable);
}
//加載字符串地址
@Override
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string);
}
//加載字uri
@Override
public RequestBuilder<Drawable> load(@Nullable Uri uri) {
return asDrawable().load(uri);
}
//加載字File
@Override
public RequestBuilder<Drawable> load(@Nullable File file) {
return asDrawable().load(file);
}
//加載字本地圖資源
@Override
public RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId) {
return asDrawable().load(resourceId);
}
//加載字url
@Override
@Deprecated
public RequestBuilder<Drawable> load(@Nullable URL url) {
return asDrawable().load(url);
}
//加載字字節(jié)數(shù)組
@Override
public RequestBuilder<Drawable> load(@Nullable byte[] model) {
return asDrawable().load(model);
}
//我們?nèi)绻恢付愋偷脑?,默認(rèn)是Drawable
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
//如果需要顯示gif時
public RequestBuilder<GifDrawable> asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
//如果需要顯示Bitmap時
public RequestBuilder<Bitmap> asBitmap() {
return as(Bitmap.class).apply(DECODE_TYPE_BITMAP);
}
public <ResourceType> RequestBuilder<ResourceType> as(
@NonNull Class<ResourceType> resourceClass) {
return new RequestBuilder<>(glide, this, resourceClass, context);
}
as asDrawable()返回的就是RequestBuilder對象。
我們以網(wǎng)絡(luò)獲取圖片為例,傳入String,看在RequestBuilder類里面的load方法
@NonNull
@Override
@CheckResult
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;
}
loadGeneric方法返回RequestBuilder本身,mode就是傳入的加載類型,也就是字符串,將mode賦值給RequestBuilder的成員變量。
isModelSet是后面用來判斷調(diào)用into方法的,必須在into之前調(diào)用load方法。
2.2 RequestBuilder
public class RequestBuilder<TranscodeType> extends BaseRequestOptions<RequestBuilder<TranscodeType>>{
protected static final RequestOptions DOWNLOAD_ONLY_OPTIONS =
new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.DATA)
.priority(Priority.LOW)
.skipMemoryCache(true);
protected RequestBuilder(
@NonNull Glide glide,
RequestManager requestManager,
//資源類型,我們以String為例,transcodeClass就是String類;
Class<TranscodeType> transcodeClass,
Context context) {
this.glide = glide;
this.requestManager = requestManager;
this.transcodeClass = transcodeClass;
this.context = context;
this.transitionOptions = requestManager.getDefaultTransitionOptions(transcodeClass);
this.glideContext = glide.getGlideContext();
initRequestListeners(requestManager.getDefaultRequestListeners());
apply(requestManager.getDefaultRequestOptions());
}
RequestBuilder繼承自BaseRequestOptions,BaseRequestOptions里面就是一些需要的配置
比如:設(shè)置是否跳過緩存,是否磁盤緩存,展位圖等。我們傳入自己的配置即可。
Glide.with(getContext())
.load(url)
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
.placeholder(R.drawable.ic_default)
.into(newDrawableImageViewTarget(mAvatarImgView));
小結(jié):
1、load方法用來傳入加載的圖片資源路徑。
2、再調(diào)load方法之前需要設(shè)置請求類型是gif或者Bitmap,不設(shè)置默認(rèn)時Drawable。
3、load之后需要設(shè)置請求的一些配置參數(shù)。是否使用緩存,展位圖等。
4、最終返回的是配置好請求類型的RequestBuilder,用來進(jìn)行下一步into調(diào)用。
3、into()方法
3.1 RequestBuilder.into()
@NonNull
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
//先判斷是否在主線程
Util.assertMainThread();
//檢測imageView是否為null
Preconditions.checkNotNull(view);
//獲取配置好的RequestOptions,再配置imageView的縮放類型。
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
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(
//構(gòu)建Target:DrawableImageViewTarget(view)或者是BitmapImageViewTarget(view)
//因為我們默認(rèn)是Drawable,所以transcodeClass是Drawable.class
glideContext.buildImageViewTarget(view, transcodeClass),
/*targetListener=*/ null,
//配置好的請求參數(shù)
requestOptions,
//主線程執(zhí)行器,Executors的構(gòu)造方法里面有:Handler handler = new Handler(Looper.getMainLooper());
Executors.mainThreadExecutor());
}
看一下GlideContext的buildImageViewTarget方法,參數(shù)是我們的控件View和最終轉(zhuǎn)碼類型的字節(jié)碼
GlideContext類是在Glide初始化的最后構(gòu)建的,用來全局提供Glide構(gòu)建的配置類對象的,比如它的getEngine()方法,返回Engine對象。
3.1.1 GlideContext.buildImageViewTarget
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass);
}
3.1.2 ImageViewTargetFactory.buildTarget
通過傳入的資源轉(zhuǎn)碼類型去創(chuàng)建不同的Target:
new BitmapImageViewTarget(view)和
new DrawableImageViewTarget(view);
*/
public class ImageViewTargetFactory {
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)");
}
}
}
3.1.3 DrawableImageViewTarget
看下DrawableImageViewTarget類,有個setResource()方法,這玩意應(yīng)該就是最后將獲取到的資源圖片顯示到控件的方法了。
public class DrawableImageViewTarget extends ImageViewTarget<Drawable> {
public DrawableImageViewTarget(ImageView view) {
super(view);
}
/** @deprecated Use {@link #waitForLayout()} instead. */
// 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);
}
}
3.1.4 Executors.mainThreadExecutor()
構(gòu)造器里創(chuàng)建了主線程的handle對象,再exectue執(zhí)行后,handle.post(command)將數(shù)據(jù)傳遞到主線程
public final class Executors {
private Executors() {
// Utility class.
}
private static final Executor MAIN_THREAD_EXECUTOR =
new Executor() {
private final Handler handler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
handler.post(command);
}
};
private static final Executor DIRECT_EXECUTOR =
new Executor() {
@Override
public void execute(@NonNull Runnable command) {
command.run();
}
};
/** Posts executions to the main thread. */
public static Executor mainThreadExecutor() {
return MAIN_THREAD_EXECUTOR;
繼續(xù)return的into方法
3.2 RequestBuilder.into()
private <Y extends Target<TranscodeType>> Y into(
//在GlideContext中創(chuàng)建的target
@NonNull Y target,
//null
@Nullable RequestListener<TranscodeType> targetListener,
//requestBuilder配置的參數(shù)
BaseRequestOptions<?> options,
//主線程執(zhí)行器
Executor callbackExecutor) {
Preconditions.checkNotNull(target);
//isModelSet的作用。
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
//通過我們傳入的參數(shù)調(diào)buildRequest方法,返回一個request,callbackExecutor含有綁定主線程的Handler
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//在給target設(shè)置request之前,看下這個target之前有沒有老的request。
Request previous = target.getRequest();
//如果兩個request等價,并且老的request有設(shè)置緩存,并且老request的不為null,并且不在Running中,就調(diào)用request的begin()方法,讓他開始加載。并返回這個target。
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
//如果上面判斷不成立。則clear老的request,將新的request設(shè)置給target。并且執(zhí)行 requestManager.track()方法。返回target。
requestManager.clear(target);
==target==.setRequest(request);
requestManager.track(target, request);
return target;
}
注意:Request類是個接口,本身有start,pause,clear,isRunning,isComplete,isEquivalentTo等方法。我們這里最終返回的Request就是后面說的==SingleRequest==對象。
** 3.2.1 說這個buildRequest方法之前,解釋一下requestManager.track這個方法**
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target);
requestTracker.runRequest(request);
}
3.2.2 看下TargetTracker類:
==TargetTracker實(shí)現(xiàn)LifecycleListener接口==,里面創(chuàng)建了一個targets集合。這個類的作用就是將所有的target添加到集合,并在生命周期變化時管理它。
public final class TargetTracker implements LifecycleListener {
// targets是一個具有映射關(guān)系的set無序集合。key就是target。
//WeakHashMap也是一種hashmap,特點(diǎn)就是它的key是弱鍵,當(dāng)key不使用的時候可以被回收。
private final Set<Target<?>> targets =
Collections.newSetFromMap(new WeakHashMap<Target<?>, Boolean>());
//追蹤,將target add到集合里面。
public void track(@NonNull Target<?> target) {
targets.add(target);
}
public void untrack(@NonNull Target<?> target) {
targets.remove(target);
}
@Override
public void onStart() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStart();
}
}
@Override
public void onStop() {
for (Target<?> target : Util.getSnapshot(targets)) {
target.onStop();
}
}
3.2.3 RequestTracker
在看 RequestTracker.runRequest方法之前,先看下RequestTracker這個類:
==RequestTracker是個管理request的工具類==
public class RequestTracker {
//將所有的request放入到一個有映射關(guān)系的set集合中,用來控制reuqest的行為
private final Set<Request> requests =Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
//排隊等待執(zhí)行的request的集合
private final List<Request> pendingRequests = new ArrayList<>();
//執(zhí)行request
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到集合
@VisibleForTesting
void addRequest(Request request) {
requests.add(request);
}
//clearAndRemove集合中的request
public boolean clearAndRemove(@Nullable Request request) {
...
}
//暫停request
public void pauseRequests() {
....
}
//暫停所有的request
public void pauseAllRequests() {
...
}
public void resumeRequests() {
...
}
public void clearRequests() {
...
}
public void restartRequests() {
....
}
}
3.2.4 再看 ==RequestTracker.runRequest==方法:
public void runRequest(@NonNull Request request) {
//將request添加到集合
//private final Set<Request> requests =
Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());====
requests.add(request);
//如果沒有暫停,執(zhí)行request的begin方法。這里request就是后面說的SingerRequest對象。
if (!isPaused) {
request.begin();
} else {
//如果在暫停,執(zhí)行clear方法 :target.removeCallback(this);
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
// private final List<Request> pendingRequests = new ArrayList<>();
//放入掛起集合里面等待
pendingRequests.add(request);
}
}
具體的執(zhí)行請求邏輯在后面的SingerRequest中。
** 3.3 繼續(xù)看RequestBuilder.buildRequest方法:**
private Request buildRequest(
Target<TranscodeType> target,
@Nullable RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
return buildRequestRecursive(
/*requestLock=*/ new Object(),
target,
targetListener,
/*parentCoordinator=*/ null,
transitionOptions,
requestOptions.getPriority(),
requestOptions.getOverrideWidth(),
requestOptions.getOverrideHeight(),
requestOptions,
callbackExecutor);
private Request buildRequestRecursive(
Object requestLock,
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(
requestLock,
target,
targetListener,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
requestOptions,
callbackExecutor);
private Request buildThumbnailRequestRecursive(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
@Nullable RequestCoordinator parentCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
BaseRequestOptions<?> requestOptions,
Executor callbackExecutor) {
...
//這里省去了許多處理縮略圖的代碼。
return obtainRequest(
requestLock,
target,
targetListener,
requestOptions,
parentCoordinator,
transitionOptions,
priority,
overrideWidth,
overrideHeight,
callbackExecutor);
}
}
3.3.1 以上代碼主要都是在處理縮略圖的。我們看主要的主線邏輯。最后return了obtainRequest方法。
private Request obtainRequest(
Object requestLock,
Target<TranscodeType> target,
RequestListener<TranscodeType> targetListener,
BaseRequestOptions<?> requestOptions,
RequestCoordinator requestCoordinator,
TransitionOptions<?, ? super TranscodeType> transitionOptions,
Priority priority,
int overrideWidth,
int overrideHeight,
Executor callbackExecutor) {
//這才是重點(diǎn),最后返回的就是這個SingleRequest對象
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
obtainRequest()方法來獲取一個Request對象.obtainRequest()方法有調(diào)用了SingleRequest.obtain方法,傳入之前配置好的參數(shù)各種參數(shù)。這些參數(shù)其實(shí)都是組裝到Request對象中了。
3.3.2 SingleRequest
==再看下SingleRequest類==,SingleRequest.obtain的之后就是SingleRequest的初始化操作并且參數(shù)賦值。這個SingleRequest就是要返回的request。
public final class SingleRequest<R> implements Request, SizeReadyCallback, ResourceCallback {
private SingleRequest(
Context context,
GlideContext glideContext,
@NonNull Object requestLock,
@Nullable Object model,
Class<R> transcodeClass,
BaseRequestOptions<?> requestOptions,
int overrideWidth,
int overrideHeight,
Priority priority,
Target<R> target,
@Nullable RequestListener<R> targetListener,
@Nullable List<RequestListener<R>> requestListeners,
RequestCoordinator requestCoordinator,
Engine engine,
TransitionFactory<? super R> animationFactory,
Executor callbackExecutor) {
this.requestLock = requestLock;
this.context = context;
this.glideContext = glideContext;
this.model = model;
this.transcodeClass = transcodeClass;
this.requestOptions = requestOptions;
this.overrideWidth = overrideWidth;
this.overrideHeight = overrideHeight;
this.priority = priority;
this.target = target;
this.targetListener = targetListener;
this.requestListeners = requestListeners;
this.requestCoordinator = requestCoordinator;
this.engine = engine;
this.animationFactory = animationFactory;
this.callbackExecutor = callbackExecutor;
status = Status.PENDING;
if (requestOrigin == null && glideContext.isLoggingRequestOriginsEnabled()) {
requestOrigin = new RuntimeException("Glide request origin trace");
}
}
==RequestTracker的runRequest中回調(diào)用begin方法(3.2.4中):==
@Override
public void begin() {
synchronized (requestLock) {
assertNotCallingCallbacks();
//確定對象沒有被回收
stateVerifier.throwIfRecycled();
startTime = LogTime.getLogTime();
// model(url)為空,回調(diào)加載失敗
if (model == null) {
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
width = overrideWidth;
height = overrideHeight;
}
}
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
//初始化狀態(tài)
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
//如果已經(jīng)設(shè)置好width
onSizeReady(overrideWidth, overrideHeight);
} else {
//通過回調(diào)去監(jiān)界面渲染完成時獲取view的大?。?ViewTreeObserver observer = view.getViewTreeObserver();)
//還是會調(diào)用onSizeReady
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));
}
}
}
3.3.3 SingleRequest.onSizeReady
SingleRequest.begin()方法是真正的請求入口;確保ImageView大小獲取到后,調(diào)用SingleRequest的onSizeReady()方法,繼續(xù):
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
if (IS_VERBOSE_LOGGABLE) {
logV("Got onSizeReady in " + LogTime.getElapsedMillis(startTime));
}
//imager的大小還不確定直接return
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));
}
//這里的engine 是在創(chuàng)建Glide的build()方法中 創(chuàng)建的(第一節(jié)1.4),engine封裝了各種Executor,內(nèi)存緩存等
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);
if (status != Status.RUNNING) {
loadStatus = null;
}
}
}
3.4 Engine
繼續(xù)Engine的load方法:
這里開始圖片的請求,圖片的三級緩存的功能也在這里
這里我們先定義一下三級緩存:
1、弱引用緩存:使用弱引用,來緩存圖片,圖片被回收后,會保存到內(nèi)存緩存中。
2、內(nèi)存緩存LruCache:(默認(rèn)是在創(chuàng)建Glide的時候創(chuàng)建的,也可自定義), 如果弱引用緩存找不到圖片,就從內(nèi)存緩存中查找,找到圖片后,刪除內(nèi)存緩存(防止因Lru的策略,圖片正在使用,但是被回收掉的問題)。
3、磁盤緩存 :上面兩級緩存都沒有圖片,如果在磁盤緩存中找到,就把圖片加載后,放到弱引用緩存中。磁盤緩存數(shù)據(jù)的種類有兩種,一種是緩存源數(shù)據(jù),這種數(shù)據(jù)需要經(jīng)過解析才能得到圖片。一種是圖片數(shù)據(jù),直接加載進(jìn)來就可以用的??梢酝ㄟ^diskCacheStrategyOf 來自由選擇如何緩存
public <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;
//生成緩存key,以后就根據(jù)這個key,在緩存中查找
EngineKey key =
keyFactory.buildKey(
model,
signature,
width,
height,
transformations,
resourceClass,
transcodeClass,
options);
//從內(nèi)存里面找是否有目標(biāo)圖片(包括弱應(yīng)用緩存和內(nèi)存緩存)
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
//如果內(nèi)存里面沒有,進(jìn)入waitForExistingOrStartNewJob方法:
if (memoryResource == null) {
return waitForExistingOrStartNewJob(
glideContext,
model,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
options,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache,
cb,
callbackExecutor,
key,
startTime);
}
}
//如果內(nèi)存中能找到,則直接回調(diào)出去
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
3.4.1
==內(nèi)存中找到的話,將數(shù)據(jù)回調(diào)到SingleReuest的onResourceReady方法,最最終通過target將展示圖片到控件。==
@GuardedBy("requestLock")
private 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;
...
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
//在這里,通過我們之前創(chuàng)建的DrawableImageViewTarget,他繼承自ImageViewTarget,ImageViewTarget有個抽象方法就是onResourceReady(),最終將將圖片顯示到控件上。
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
3.5 從內(nèi)存里面找
@Nullable
private EngineResource<?> loadFromMemory(
EngineKey key, boolean isMemoryCacheable, long startTime) {
if (!isMemoryCacheable) {
return null;
}
//檢查是弱引用緩存中否有目標(biāo)圖片
EngineResource<?> active = loadFromActiveResources(key);
if (active != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from active resources", startTime, key);
}
return active;
}
//檢查內(nèi)存的緩存 是否有目標(biāo)圖片
EngineResource<?> cached = loadFromCache(key);
if (cached != null) {
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Loaded resource from cache", startTime, key);
}
return cached;
}
return null;
}
3.5.1 Engine.loadFromActiveResources()
@Nullable
private EngineResource<?> loadFromActiveResources(Key key) {
//activeResources獲取弱應(yīng)用緩存
EngineResource<?> active = activeResources.get(key);
if (active != null) {
active.acquire();
}
return active;
}
3.5.2 ActiveResources 弱引用緩存
class ActiveResources {
//這個map就是ActiveResources里面用來保存弱應(yīng)用緩存的
Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
@Nullable
synchronized EngineResource<?> get(Key key) {
ResourceWeakReference activeRef = activeEngineResources.get(key);
if (activeRef == null) {
return null;
}
//找到弱應(yīng)用對象,get到EngineResource返回
EngineResource<?> active = activeRef.get();
if (active == null) {
cleanupActiveReference(activeRef);
}
return active;
}
//ResourceWeakReference是ActiveResources的內(nèi)部類,繼承WeakReference
static final class ResourceWeakReference extends WeakReference<EngineResource<?>> {
final Key key;//緩存key
final boolean isCacheable;
Resource<?> resource;//緩存resource
}
ActiveResources是保存活動資源的一個類,它里面有個內(nèi)部類ResourceWeakReference,這個ResourceWeakReference繼承WeakReference。
這個ActiveResources里面有一個value是ResourceWeakReference類型的map,它主要保存的就是活動的資源,我們叫他弱應(yīng)用緩存。緩存是先從弱應(yīng)用緩存中查找,沒找到再去內(nèi)存緩存中查找。
再看下這個弱應(yīng)用緩存是什么時候存進(jìn)去的?
//1、弱應(yīng)用緩存沒找到,就會去內(nèi)存緩存找,內(nèi)存緩存找到后保存到弱應(yīng)用緩存
private EngineResource<?> loadFromCache(Key key) {
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
//這個方法就是往弱應(yīng)用緩存map中存數(shù)據(jù)
activeResources.activate(key, cached);
}
return cached;
}
//2、當(dāng)內(nèi)存緩存中都沒有找到,那就去磁盤中找,在沒有的就去網(wǎng)絡(luò)獲取,這時候獲取到資源并且展示完成后再存到弱應(yīng)用緩存中。
@Override
public synchronized void onEngineJobComplete(
EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
// A null resource indicates that the load failed, usually due to an exception.
if (resource != null && resource.isMemoryCacheable()) {
activeResources.activate(key, resource);
}
jobs.removeIfCurrent(key, engineJob);
}
3.6 如果緩存里面沒有,則走下面方法,從磁盤或者網(wǎng)絡(luò)獲取
//執(zhí)行一個新的job
private <R> LoadStatus waitForExistingOrStartNewJob(
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,
EngineKey key,
long startTime) {
//在弱引用和內(nèi)存緩存中,都沒有找到圖片,就執(zhí)行任務(wù)。
//這個任務(wù),會現(xiàn)在磁盤緩存中查找,因為磁盤讀取耗時較大,所以放在任務(wù)線程中
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
//如果current不等于null,說明這個engineJob已經(jīng)在執(zhí)行了,不用再次構(gòu)建
if (current != null) {
current.addCallback(cb, callbackExecutor);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Added to existing load", startTime, key);
}
return new LoadStatus(cb, current);
}
//創(chuàng)建一個新的engineJob對象,它里面有很多Executor,用來加載異步圖片
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
//創(chuàng)建一個解碼工作的decodeJob,用于解碼圖片的
DecodeJob<R> decodeJob =
decodeJobFactory.build(
glideContext,
model,
key,
signature,
width,
height,
resourceClass,
transcodeClass,
priority,
diskCacheStrategy,
transformations,
isTransformationRequired,
isScaleOnlyOrNoTransform,
onlyRetrieveFromCache,
options,
engineJob);
// 放在Jobs內(nèi)部維護(hù)的存放任務(wù)的HashMap中(3.6.1),
jobs.put(key, engineJob);
// 注冊ResourceCallback接口,就是在成功獲取圖片后,需要顯示到ImageView 上的回調(diào),這個接口回調(diào)到SingleRequest 中
engineJob.addCallback(cb, callbackExecutor);
//開始執(zhí)行
engineJob.start(decodeJob);
if (VERBOSE_IS_LOGGABLE) {
logWithTimeAndKey("Started new load", startTime, key);
}
return new LoadStatus(cb, engineJob);
}
3.6.1 Jobs
Jobs里面維護(hù)了兩個map,一個新job,一個緩存job。
final class Jobs {
private final Map<Key, EngineJob<?>> jobs = new HashMap<>();
private final Map<Key, EngineJob<?>> onlyCacheJobs = new HashMap<>();
@VisibleForTesting
Map<Key, EngineJob<?>> getAll() {
return Collections.unmodifiableMap(jobs);
}
EngineJob<?> get(Key key, boolean onlyRetrieveFromCache) {
return getJobMap(onlyRetrieveFromCache).get(key);
}
void put(Key key, EngineJob<?> job) {
getJobMap(job.onlyRetrieveFromCache()).put(key, job);
}
void removeIfCurrent(Key key, EngineJob<?> expected) {
Map<Key, EngineJob<?>> jobMap = getJobMap(expected.onlyRetrieveFromCache());
if (expected.equals(jobMap.get(key))) {
jobMap.remove(key);
}
}
private Map<Key, EngineJob<?>> getJobMap(boolean onlyRetrieveFromCache) {
return onlyRetrieveFromCache ? onlyCacheJobs : jobs;
}
}
3.7 繼續(xù)EngineJob中的start方法:
public synchronized void start(DecodeJob<R> decodeJob) {
this.decodeJob = decodeJob;
//若能從磁盤緩存獲取數(shù)據(jù),就使用diskCacheExecutor,否則在根據(jù)其他的條件判斷使用哪個Executor
//ture:有緩存,則使用磁盤緩存線程池。否則返回數(shù)據(jù)源線程池;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
//執(zhí)行decodeJob的run方法
executor.execute(decodeJob);
}
通過上面start()方法知道是去磁盤取還是網(wǎng)絡(luò)獲取,對應(yīng)執(zhí)行器再去執(zhí)行這個decodeJob。
3.8 DecodeJob
這個類負(fù)責(zé)從磁盤或數(shù)據(jù)源解碼資源,并應(yīng)用轉(zhuǎn)換和轉(zhuǎn)碼。
在看下DecodeJob的willDecodeFromCache方法:
boolean willDecodeFromCache() {
Stage firstStage = getNextStage(Stage.INITIALIZE);
//如果此作業(yè)將嘗試從磁盤緩存解碼資源,則返回 true,如果它始終從源解碼,則返回 false。
return firstStage == Stage.RESOURCE_CACHE || firstStage == Stage.DATA_CACHE;
}
3.8.1 獲取下一個階段從哪里獲取數(shù)據(jù)
private Stage getNextStage(Stage current) {
switch (current) {
//若配置的緩存策略允許從磁盤緩存的資源中讀取數(shù)據(jù),則返回Stage.RESOURCE_CACHE
case INITIALIZE:
return diskCacheStrategy.decodeCachedResource()
? Stage.RESOURCE_CACHE
: getNextStage(Stage.RESOURCE_CACHE);
//若配置的緩存策略允許從磁盤緩存的源數(shù)據(jù)緩存讀取數(shù)據(jù),則返回Stage.DATA_CACHE
case RESOURCE_CACHE:
return diskCacheStrategy.decodeCachedData()
? Stage.DATA_CACHE
: getNextStage(Stage.DATA_CACHE);
//若只能允許從緩存中讀取數(shù)據(jù),則直接FINISH,否則返回Stage.SOURCE,表示加載新的資源
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);
}
}
注意:磁盤緩存了兩種資源,一種是數(shù)據(jù)源緩存,一種是磁盤的資源緩存
3.8.2 DecodeJob.run()
public void run() {
GlideTrace.beginSectionFormat("DecodeJob#run(model=%s)", model);
DataFetcher<?> localFetcher = currentFetcher;
try {
if (isCancelled) {
notifyFailed();
return;
}
//主要看這:
runWrapped();
} catch (CallbackException e) {
} finally {
if (localFetcher != null) {
localFetcher.cleanup();
}
GlideTrace.endSection();
}
}
3.8.3 DecodeJob.runWrapped():
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
//獲取下一階段的狀態(tài)
stage = getNextStage(Stage.INITIALIZE);
//根據(jù)下一階段狀態(tài),判斷具體有哪個類執(zhí)行
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
首先從磁盤中去數(shù)據(jù)。如果磁盤的資源緩存或者磁盤的數(shù)據(jù)源緩存任意一個沒有取到緩存,則就去網(wǎng)絡(luò)請求數(shù)據(jù)。
該類繼承了DataFetcherGenerator, 這是一個數(shù)據(jù)獲取生成器。
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);
}
}
這三個數(shù)據(jù)抓取執(zhí)行器分別是:磁盤資源緩存執(zhí)行器、磁盤數(shù)據(jù)源執(zhí)行器、網(wǎng)絡(luò)元數(shù)據(jù)執(zhí)行器;通過這個stage去選擇哪一個執(zhí)行器。
3.8.4 DecodeJob.runGenerators()
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//判斷邏輯主要看startNext方法,這個方法回去執(zhí)行不同執(zhí)行器的startNext方法。
// 返回值是個布爾值,如果返回true,說明剛才的執(zhí)行器獲取到了緩存,然后去解碼,回調(diào)出去,如果返回false,則執(zhí)行Stage.SOURCE的邏輯,走reschedule()方法
while (!isCancelled&& currentGenerator != null && !(isStarted = currentGenerator.startNext())) {
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
@Override
public void reschedule() {
//我們想從磁盤緩存服務(wù)切換到源執(zhí)行器。
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
runReason改變之后,reschedule方法執(zhí)行的就是網(wǎng)絡(luò)獲取執(zhí)行器的邏輯了,
3.8.5 獲取網(wǎng)絡(luò)圖片
所以執(zhí)行SourceGenerator.startNext方法:
@Override
public boolean startNext() {
...
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
//從DecodeHelper的數(shù)據(jù)加載集合中, 獲取一個數(shù)據(jù)加載器 ModelLoader
//這些ModelLoader 包括默認(rèn)的和自定義的
// 這里的符合條件就是判斷在load()傳入的對象類型,是否可以被ModelLoader所處理
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
startNextLoad(loadData);
}
}
return started;
}
3.8.6 DecodeHelp獲取loadData傳入startNextLoad方法:
List<LoadData<?>> getLoadData() {
if (!isLoadDataSet) {
isLoadDataSet = true;
loadData.clear();
//從Glide注冊的register中獲取modelLoaders
List<ModelLoader<Object, ?>> modelLoaders = glideContext.getRegistry().getModelLoaders(model);
//遍歷modelLoaders
for (int i = 0, size = modelLoaders.size(); i < size; i++) {
//此時的model為url的string格式,返回該其中一個實(shí)現(xiàn)類為StringLoader
ModelLoader<Object, ?> modelLoader = modelLoaders.get(i);
//通過函數(shù)buildLoadData 來創(chuàng)建LoadData
LoadData<?> current = modelLoader.buildLoadData(model, width, height, options);
if (current != null) {
loadData.add(current);
}
}
}
return loadData;
}
3.8.7 startNextLoad()
繼續(xù)查看 startNextLoad()方法接著通過LoadData對象內(nèi)部的 fetcher ,來進(jìn)行實(shí)際的請求操作(例如發(fā)起網(wǎng)絡(luò)請求)
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
** 3.8.8 **
接著上面 loadData.fetcher.loadData邏輯,他是最終獲取資源的,比如網(wǎng)絡(luò)請求數(shù)據(jù),fetcher是HttpUrlFetcher:
@Override
public void loadData(
@NonNull Priority priority, @NonNull DataCallback<? super InputStream> callback) {
long startTime = LogTime.getLogTime();
try {
//網(wǎng)絡(luò)請求數(shù)據(jù)
InputStream result = loadDataWithRedirects(glideUrl.toURL(), 0, null, glideUrl.getHeaders());
//數(shù)據(jù)獲取成功的回調(diào)
callback.onDataReady(result);
} catch (IOException e) {
callback.onLoadFailed(e);
} finally {
}
}
** 3.8.9 **
執(zhí)行網(wǎng)絡(luò)請求返回數(shù)據(jù)流
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 {
// Comparing the URLs using .equals performs additional network I/O and is generally broken.
// See http://michaelscharf.blogspot.com/2006/11/javaneturlequals-and-hashcode-make.html.
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);
// Stop the urlConnection instance of HttpUrlConnection from following redirects so that
// redirects will be handled by recursive calls to this method, loadDataWithRedirects.
urlConnection.setInstanceFollowRedirects(false);
// Connect explicitly to avoid errors in decoders if connection fails.
urlConnection.connect();
// Set the stream so that it's closed in cleanup to avoid resource leaks. See #2352.
stream = urlConnection.getInputStream();
if (isCancelled) {
return null;
}
final int statusCode = urlConnection.getResponseCode();
if (isHttpOk(statusCode)) {
return getStreamForSuccessfulRequest(urlConnection);
} else if (isHttpRedirect(statusCode)) {
String redirectUrlString = urlConnection.getHeaderField("Location");
if (TextUtils.isEmpty(redirectUrlString)) {
throw new HttpException("Received empty or null redirect url");
}
URL redirectUrl = new URL(url, redirectUrlString);
// Closing the stream specifically is required to avoid leaking ResponseBodys in addition
// to disconnecting the url connection below. See #2352.
cleanup();
return loadDataWithRedirects(redirectUrl, redirects + 1, url, headers);
} else if (statusCode == INVALID_STATUS_CODE) {
throw new HttpException(statusCode);
} else {
throw new HttpException(urlConnection.getResponseMessage(), statusCode);
}
}
** 3.8.10 **
請求數(shù)據(jù)成功后, callback.onDataReady(result)在SourceGenerator的startNextLoad里面(3.8.7)接收回調(diào)數(shù)據(jù),
private void startNextLoad(final LoadData<?> toStart) {
loadData.fetcher.loadData(
helper.getPriority(),
new DataCallback<Object>() {
@Override
public void onDataReady(@Nullable Object data) {
if (isCurrentRequest(toStart)) {
onDataReadyInternal(toStart, data);
}
}
@Override
public void onLoadFailed(@NonNull Exception e) {
if (isCurrentRequest(toStart)) {
onLoadFailedInternal(toStart, e);
}
}
});
}
**3.9 **
這時候數(shù)據(jù)已經(jīng)請求到了,執(zhí)行onDataReadyInternal方法,參數(shù)有l(wèi)oadDate和請求到的數(shù)據(jù)
@SuppressWarnings("WeakerAccess")
@Synthetic
void onDataReadyInternal(LoadData<?> loadData, Object data) {
DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
//如果該數(shù)據(jù)類型,有啟用磁盤緩存,就把值賦給dataToCache
if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
dataToCache = data;
//調(diào)用DecodeJob的reschedule,用線程池執(zhí)行任務(wù),實(shí)際上就是再次調(diào)用SourceGenerator的startNext
cb.reschedule();
} else {
// 繼續(xù)回調(diào)FetcherReadyCallback的onDataFetcherReady方法,將data回調(diào)出去
cb.onDataFetcherReady(
loadData.sourceKey,
data,
loadData.fetcher,
loadData.fetcher.getDataSource(),
originalKey);
}
}
3.9.1 解析數(shù)據(jù)
這個回調(diào)方法走的是DecodeJob.onDataFetcherReady(),DecodeJob類實(shí)現(xiàn)了FetcherReadyCallback接口。
然后解析數(shù)據(jù)
@Override
public void reschedule() {
runReason = RunReason.SWITCH_TO_SOURCE_SERVICE;
callback.reschedule(this);
}
@Override
public void onDataFetcherReady(
Key sourceKey, Object data, DataFetcher<?> fetcher, DataSource dataSource, Key attemptedKey) {
this.currentSourceKey = sourceKey;
this.currentData = data;
this.currentFetcher = fetcher;
this.currentDataSource = dataSource;
this.currentAttemptingKey = attemptedKey;
if (Thread.currentThread() != currentThread) {
runReason = RunReason.DECODE_DATA;
callback.reschedule(this);
} else {
GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
try {
//解析獲取到的數(shù)據(jù)
decodeFromRetrievedData();
} finally {
GlideTrace.endSection();
}
}
}
3.9.2
DecodeJob.decodeFromRetrievedData
==解析得到資源==
private void decodeFromRetrievedData() {
Resource<R> resource = null;
try {
// 從數(shù)據(jù)中解碼得到資源
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
...
}
// 最終得到的Resource<Drawable>對象,
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
至此:得到了網(wǎng)絡(luò)請求的數(shù)據(jù),并解析后得到了資源
3.9.3
看下怎么解析數(shù)據(jù)的
private <Data> Resource<R> decodeFromData(
DataFetcher<?> fetcher, Data data, DataSource dataSource) throws GlideException {
try {
if (data == null) {
return null;
}
long startTime = LogTime.getLogTime();
//繼續(xù)解析數(shù)據(jù)
Resource<R> result = decodeFromFetcher(data, dataSource);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey("Decoded result " + result, startTime);
}
return result;
} finally {
fetcher.cleanup();
}
}
這里的data 是一個泛型,本例中是 Stream 流,從http請求獲取到的
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource){
LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
//通過解析器來解析數(shù)據(jù)
return runLoadPath(data, dataSource, path);
}
上面代碼看出:
1、獲取一個LoadPath,它是根據(jù)數(shù)據(jù)類型(這里是stream),ResourceDecoder(資源解碼),transcoder(資源轉(zhuǎn)碼)
2、從這些參數(shù)可以看出,最終把數(shù)據(jù)流轉(zhuǎn)為Bitmap 或Drawable ,就是在LoadPath中進(jìn)行的,這里是指DecodePath
private <Data, ResourceType> Resource<R> runLoadPath(
Data data, DataSource dataSource, LoadPath<Data, ResourceType, R> path)
throws GlideException {
Options options = getOptionsWithHardwareConfig(dataSource);
//此時的data為InputStream對象,故rewinder為InputStreamRewinder對象
DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
try {
//執(zhí)行LoadPath 的load ,進(jìn)行解碼,轉(zhuǎn)換操作
return path.load(
rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
} finally {
rewinder.cleanup();
}
}
3.9.4
LoadPath.load() 解析數(shù)據(jù)
public Resource<Transcode> load(
{
...參數(shù)省略...
return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
} finally {
listPool.release(throwables);
}
}
重點(diǎn)在下面方法:正真的解碼
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 {
//重點(diǎn):調(diào)用DecodePath.decode真正進(jìn)行數(shù)據(jù)解析
result = path.decode(rewinder, width, height, options, decodeCallback);
} catch (GlideException e) {
exceptions.add(e);
}
if (result != null) {
break;
}
}
if (result == null) {
throw new GlideException(failureMessage, new ArrayList<>(exceptions));
}
return result;
}
解碼邏輯:
public Resource<Transcode> decode(
DataRewinder<DataType> rewinder,
int width,
int height,
@NonNull Options options,
DecodeCallback<ResourceType> callback)
throws GlideException {
//獲取到Resource<BItmap>對象
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
// 這個方法是回調(diào)到Decodejob.onResourceDecoded ,作用是調(diào)用RequestOptions中的Transform處理圖片,然后將ResourceCache的Key和Encode準(zhǔn)備好(放在變量 deferEncoderManager中),最后將這個源數(shù)據(jù)進(jìn)行寫入磁盤緩存。
//這就是磁盤的源數(shù)據(jù)緩存。
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
//進(jìn)行數(shù)據(jù)類型的轉(zhuǎn)換
return transcoder.transcode(transformed, options);
}
@NonNull
private Resource<ResourceType> decodeResource(
DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options)
throws GlideException {
List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
try {
return decodeResourceWithList(rewinder, width, height, options, exceptions);
} finally {
listPool.release(exceptions);
}
}
3.9.5
繼續(xù)decodeResourceWithList方法:decoder是一個ResourceDecoder接口(資源解碼器),根據(jù)不同的DataType和ResourceType它會有不同的實(shí)現(xiàn)類,這里的實(shí)現(xiàn)類是ByteBufferBitmapDecoder
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();
//根據(jù)DataType和ResourceType的類型分發(fā)給不同的解碼器Decoder
result = decoder.decode(data, width, height, options);
}
} catch (IOException | RuntimeException |
}
return result;
}
3.9.6
ByteBufferBitmapDecoder的decode方法,
里面有個downsampler類,downsampler主要是對流進(jìn)行解碼,旋轉(zhuǎn),壓縮,圓角等處理
public class ByteBufferBitmapDecoder implements ResourceDecoder<ByteBuffer, Bitmap> {
private final Downsampler downsampler;
public ByteBufferBitmapDecoder(Downsampler downsampler) {
this.downsampler = downsampler;
}
@Override
public boolean handles(@NonNull ByteBuffer source, @NonNull Options options) {
return downsampler.handles(source);
}
@Override
public Resource<Bitmap> decode(
@NonNull ByteBuffer source, int width, int height, @NonNull Options options)
throws IOException {
InputStream is = ByteBufferUtil.toStream(source);
//downsampler主要是對流進(jìn)行解碼,旋轉(zhuǎn),壓縮,圓角等處理
return downsampler.decode(is, width, height, options);
}
}
3.9.7
繼續(xù)DownSampler中的decode方法,省去多次跳轉(zhuǎn):
private Resource<Bitmap> decode(
ImageReader imageReader,
int requestedWidth,
int requestedHeight,
Options options,
DecodeCallbacks callbacks)
throws IOException {
byte[] bytesForOptions = byteArrayPool.get(ArrayPool.STANDARD_BUFFER_SIZE_BYTES, byte[].class);
BitmapFactory.Options bitmapFactoryOptions = getDefaultOptions();
bitmapFactoryOptions.inTempStorage = bytesForOptions;
DecodeFormat decodeFormat = options.get(DECODE_FORMAT);
PreferredColorSpace preferredColorSpace = options.get(PREFERRED_COLOR_SPACE);
DownsampleStrategy downsampleStrategy = options.get(DownsampleStrategy.OPTION);
boolean fixBitmapToRequestedDimensions = options.get(FIX_BITMAP_SIZE_TO_REQUESTED_DIMENSIONS);
boolean isHardwareConfigAllowed =
options.get(ALLOW_HARDWARE_CONFIG) != null && options.get(ALLOW_HARDWARE_CONFIG);
try {
//得到解析后的bitmap
Bitmap result =
decodeFromWrappedStreams(
imageReader,
bitmapFactoryOptions,
downsampleStrategy,
decodeFormat,
preferredColorSpace,
isHardwareConfigAllowed,
requestedWidth,
requestedHeight,
fixBitmapToRequestedDimensions,
callbacks);
//把bitmap 封裝進(jìn)Resource ,返回Resource 對象
return BitmapResource.obtain(result, bitmapPool);
} finally {
releaseOptions(bitmapFactoryOptions);
byteArrayPool.put(bytesForOptions);
}
}
3.9.8 DownSampler.decodeFromWrappedStreams()
下面進(jìn)入到decodeFromWrappedStreams 來看一下,這里涉及到bitmap在bitmapPool中的復(fù)用(==圖片復(fù)用僅支持大小相同的位圖==),目的是 如果bitmapPool 有可用的bitmap,就復(fù)用該bitmap。避免為Bitmap 分配內(nèi)存,導(dǎo)致內(nèi)存抖動
private Bitmap decodeFromWrappedStreams(
ImageReader imageReader,
BitmapFactory.Options options,
DownsampleStrategy downsampleStrategy,
DecodeFormat decodeFormat,
PreferredColorSpace preferredColorSpace,
boolean isHardwareConfigAllowed,
int requestedWidth,
int requestedHeight,
boolean fixBitmapToRequestedDimensions,
DecodeCallbacks callbacks)
throws IOException {
long startTime = LogTime.getLogTime();
int[] sourceDimensions = getDimensions(imageReader, options, callbacks, bitmapPool);
int sourceWidth = sourceDimensions[0];
int sourceHeight = sourceDimensions[1];
String sourceMimeType = options.outMimeType;
if (sourceWidth == -1 || sourceHeight == -1) {
isHardwareConfigAllowed = false;
}
int orientation = imageReader.getImageOrientation();
int degreesToRotate = TransformationUtils.getExifOrientationDegrees(orientation);
boolean isExifOrientationRequired = TransformationUtils.isExifOrientationRequired(orientation);
int targetWidth =
requestedWidth == Target.SIZE_ORIGINAL
? (isRotationRequired(degreesToRotate) ? sourceHeight : sourceWidth)
: requestedWidth;
int targetHeight =
requestedHeight == Target.SIZE_ORIGINAL
? (isRotationRequired(degreesToRotate) ? sourceWidth : sourceHeight)
: requestedHeight;
ImageType imageType = imageReader.getImageType();
//計算縮放比例,結(jié)果會體現(xiàn)在options參數(shù)中
calculateScaling(
imageType,
imageReader,
callbacks,
bitmapPool,
downsampleStrategy,
degreesToRotate,
sourceWidth,
sourceHeight,
targetWidth,
targetHeight,
options);
calculateConfig(
imageReader,
decodeFormat,
isHardwareConfigAllowed,
isExifOrientationRequired,
options,
targetWidth,
targetHeight);
//計算sdk版本是否大于KITKAT,在該系統(tǒng)及之前 圖片復(fù)用僅支持大小相同的位圖
boolean isKitKatOrGreater = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// Prior to KitKat, the inBitmap size must exactly match the size of the bitmap we're decoding.
//下面的判斷,來計算是否在BitmapPool中 是否有bitmap可以被復(fù)用,如果有就把bitmap 設(shè)置到options.inBitmap,
//這樣在根據(jù)options 去解析生成bitmap的時候,就不需要再次分配內(nèi)存了,
if ((options.inSampleSize == 1 || isKitKatOrGreater) && shouldUsePool(imageType)) {
int expectedWidth;
int expectedHeight;
if (sourceWidth >= 0
&& sourceHeight >= 0
&& fixBitmapToRequestedDimensions
&& isKitKatOrGreater) {
expectedWidth = targetWidth;
expectedHeight = targetHeight;
} else {
float densityMultiplier =
isScaling(options) ? (float) options.inTargetDensity / options.inDensity : 1f;
int sampleSize = options.inSampleSize;
int downsampledWidth = (int) Math.ceil(sourceWidth / (float) sampleSize);
int downsampledHeight = (int) Math.ceil(sourceHeight / (float) sampleSize);
expectedWidth = Math.round(downsampledWidth * densityMultiplier);
expectedHeight = Math.round(downsampledHeight * densityMultiplier);
if (expectedWidth > 0 && expectedHeight > 0) {
//該函數(shù)會在bitmapPool中查找符合大小的bitmap ,如果找到了就設(shè)置給inBitmap
setInBitmap(options, bitmapPool, expectedWidth, expectedHeight);
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
boolean isP3Eligible =
preferredColorSpace == PreferredColorSpace.DISPLAY_P3
&& options.outColorSpace != null
&& options.outColorSpace.isWideGamut();
options.inPreferredColorSpace =
ColorSpace.get(isP3Eligible ? ColorSpace.Named.DISPLAY_P3 : ColorSpace.Named.SRGB);
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
options.inPreferredColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
}
//根據(jù)options 把流解析為Bitmap
Bitmap downsampled = decodeStream(imageReader, options, callbacks, bitmapPool);
callbacks.onDecodeComplete(bitmapPool, downsampled);
Bitmap rotated = null;
if (downsampled != null) {
downsampled.setDensity(displayMetrics.densityDpi);
rotated = TransformationUtils.rotateImageExif(bitmapPool, downsampled, orientation);
if (!downsampled.equals(rotated)) {
bitmapPool.put(downsampled);
}
}
//rotated就是最后解析后的bitmap。
return rotated;
}
至此已經(jīng)得到了解析后的資源了,接下來就是要顯示到指定的ImageView控件上.
4.1
接下來就是==將怎樣將bitmap顯示到控件的邏輯了。==
DecodeJob.decodeFromRetrievedData()
回到DecodeJob的decodeFromRetrievedData方法,解碼后的resource不等于null時,調(diào)用notifyEncodeAndRelease方法:
private void decodeFromRetrievedData() {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
logWithTimeAndKey(
"Retrieved data",
startFetchTime,
"data: "
+ currentData
+ ", cache key: "
+ currentSourceKey
+ ", fetcher: "
+ currentFetcher);
}
Resource<R> resource = null;
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource);
} catch (GlideException e) {
e.setLoggingDetails(currentAttemptingKey, currentDataSource);
throwables.add(e);
}
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource);
} else {
runGenerators();
}
}
4.2
DecodeJob.notifyEncodeAndRelease
緩存資源,通知主線程顯示
private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
if (resource instanceof Initializable) {
((Initializable) resource).initialize();
}
Resource<R> result = resource;
LockedResource<R> lockedResource = null;
if (deferredEncodeManager.hasResourceToEncode()) {
lockedResource = LockedResource.obtain(resource);
result = lockedResource;
}
// 通知主線程回調(diào),加載圖片
notifyComplete(result, dataSource);
// 更新狀態(tài)為編碼
stage = Stage.ENCODE;
try {
if (deferredEncodeManager.hasResourceToEncode()) {
//將轉(zhuǎn)碼好的資源緩存到磁盤,這就是磁盤的額資源緩存。
deferredEncodeManager.encode(diskCacheProvider, options);
}
} finally {
if (lockedResource != null) {
lockedResource.unlock();
}
}
onEncodeComplete();
}
4.2.1 執(zhí)行DecodeJob.notifyComplete() 將resourse回調(diào)到 EngineJob的onResourceReady()
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
//這個callback 就是 EngineJob對象,是在創(chuàng)建Decodejob的時候傳遞進(jìn)來
callback.onResourceReady(resource, dataSource);
}
4.3 EngineJob.onResourceReady()
接下來看EngineJob中onResourceReady方法:
@Override
public void onResourceReady(Resource<R> resource, DataSource dataSource) {
synchronized (this) {
this.resource = resource;
this.dataSource = dataSource;
}
notifyCallbacksOfResult();
}
4.4 EngineJob.notifyCallbacksOfResult()
public void notifyCallbacksOfResult() {
ResourceCallbacksAndExecutors copy;
Key localKey;
EngineResource<?> localResource;
synchronized (this) {
stateVerifier.throwIfRecycled();
...
engineResource = engineResourceFactory.build(resource, isCacheable, key, resourceListener);
hasResource = true;
copy = cbs.copy();
incrementPendingCallbacks(copy.size() + 1);
localKey = key;
localResource = engineResource;
}
//這里就是把解析后的圖片,也就是即將要顯示出來的圖片,緩存到弱引用緩存中
engineJobListener.onEngineJobComplete(this, localKey, localResource);
for (final ResourceCallbackAndExecutor entry : copy) {
//遍歷每一個回調(diào)接口,entry.cb 就是SingleRequest 對象,執(zhí)行接口ResourceCallback的run方法
entry.executor.execute(new CallResourceReady(entry.cb));
}
decrementPendingCallbacks();
}
看下CallResourceReady接口,定義在EngineJob中:
private class CallResourceReady implements Runnable {
private final ResourceCallback cb;
CallResourceReady(ResourceCallback cb) {
this.cb = cb;
}
@Override
public void run() {
synchronized (cb.getLock()) {
synchronized (EngineJob.this) {
if (cbs.contains(cb)) {
engineResource.acquire();
//執(zhí)行回調(diào)
callCallbackOnResourceReady(cb);
removeCallback(cb);
}
decrementPendingCallbacks();
}
}
}
}
void callCallbackOnResourceReady(ResourceCallback cb) {
try {
//cb 就是SingleRequest 對象,所以下面去它里面看onResourceReady
cb.onResourceReady(engineResource, dataSource);
} catch (Throwable t) {
throw new CallbackException(t);
}
}
SingleRequest對象的onResourceReady方法,他是ResourceCallback接口定義方法
public void onResourceReady(Resource<?> resource, DataSource dataSource) {
stateVerifier.throwIfRecycled();
Resource<?> toRelease = null;
...
onResourceReady((Resource<R>) resource, (R) received, dataSource);
} finally {
if (toRelease != null) {
engine.release(toRelease);
}
}
}
private void onResourceReady(Resource<R> resource, R result, DataSource dataSource) {
boolean isFirstResource = isFirstReadyResource();
status = Status.COMPLETE;
this.resource = resource;
isCallingCallbacks = true;
try {
...
if (!anyListenerHandledUpdatingTarget) {
Transition<? super R> animation = animationFactory.build(dataSource, isFirstResource);
//target 函數(shù)是在 buildTarget 時,創(chuàng)建的
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
ImageViewTarget的onResourceReady方法,ImageViewTarget是一個抽象類,BitmapImageViewTarget繼承它
@Override
public void onResourceReady(@NonNull Z resource, @Nullable Transition<? super Z> transition) {
if (transition == null || !transition.transition(resource, this)) {
setResourceInternal(resource);
} else {
maybeUpdateAnimatable(resource);
}
}
private void setResourceInternal(@Nullable Z resource) {
//抽象方法,執(zhí)行不同的實(shí)現(xiàn),我們是以BitmapImageViewTarget為例:
setResource(resource);
maybeUpdateAnimatable(resource);
}
private void maybeUpdateAnimatable(@Nullable Z resource) {
if (resource instanceof Animatable) {
animatable = (Animatable) resource;
animatable.start();
} else {
animatable = null;
}
}
protected abstract void setResource(@Nullable Z resource);
}
BitmapImageViewTarget中顯示資源,把圖片設(shè)置到ImageView中
*/
@Override
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
終于啃完了,比較費(fèi)事,如果發(fā)現(xiàn)哪里有錯誤,煩請指出~~~加油,奧利蓋~~~
至此,完結(jié)...