提示: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對象,它有好幾個(gè)方法重載至壤,我們來看一下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) {
//必須要有一個(gè)上下文才能加載
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);
//這個(gè)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)建了一個(gè)RequestManagerRetriever對象
RequestManagerRetriever requestManagerRetriever =
new RequestManagerRetriever(requestManagerFactory);
//構(gòu)建Glide對象黎棠,并將上面初始化時(shí)創(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)置的一個(gè)不可見的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) {
//這個(gè)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是一個(gè)接口,build方法的參數(shù)里面?zhèn)魅肓薒ifecycle對象扛门。這個(gè)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類中看似有很多個(gè)get()方法的重載纵寝,什么Context參數(shù),Activity參數(shù)星立,F(xiàn)ragment參數(shù)等等爽茴,實(shí)際上只有兩種情況而已,即傳入Application類型的參數(shù)绰垂,和傳入非Application類型的參數(shù)室奏。
如果在Glide.with()方法中傳入的是一個(gè)Application對象,它自動(dòng)就是和應(yīng)用程序的生命周期是同步的劲装,如果應(yīng)用程序關(guān)閉的話胧沫,Glide的加載也會(huì)同時(shí)終止。
如果在Glide.with()方法中傳入非Application參數(shù)占业,那就是會(huì)向當(dāng)前的Activity當(dāng)中添加一個(gè)隱藏的Fragment绒怨,這個(gè)隱藏的Fragment的生命周期就和當(dāng)前Activity的生命周期綁定了。
如果我們是在非主線程當(dāng)中使用的Glide谦疾,那么不管你是傳入的Activity還是Fragment南蹂,都會(huì)被強(qiáng)制當(dāng)成Application來處理。
界面不可見或者銷毀的時(shí)候念恍,通過這樣的方法還能避免Glide持有Activity的實(shí)例而發(fā)生內(nèi)存泄漏問題六剥。
小結(jié):
with()方法傳入當(dāng)前環(huán)境晚顷,是為了讓圖片加載保持生命周期同步。并且返回RequestManager對象供load()方法使用疗疟。RequestManager能夠用于管理和啟動(dòng)對Glide的請求该默。還可以控制生命周期事件智能地停止,啟動(dòng)和重新啟動(dòng)請求.
2策彤、load()方法
2.1 RequestManager.load()
因?yàn)間ilde支持很多圖片來源权均。所以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)绻恢付愋偷脑掃瓷蓿J(rèn)是Drawable
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class);
}
//如果需要顯示gif時(shí)
public RequestBuilder<GifDrawable> asGif() {
return as(GifDrawable.class).apply(DECODE_TYPE_GIF);
}
//如果需要顯示Bitmap時(shí)
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)時(shí)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)
//因?yàn)槲覀兡J(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類建炫,有個(gè)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方法衍慎,返回一個(gè)request,callbackExecutor含有綁定主線程的Handler
Request request = buildRequest(target, targetListener, options, callbackExecutor);
//在給target設(shè)置request之前,看下這個(gè)target之前有沒有老的request皮钠。
Request previous = target.getRequest();
//如果兩個(gè)request等價(jià)稳捆,并且老的request有設(shè)置緩存,并且老request的不為null麦轰,并且不在Running中乔夯,就調(diào)用request的begin()方法,讓他開始加載原朝。并返回這個(gè)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類是個(gè)接口,本身有start聋涨,pause晾浴,clear,isRunning牍白,isComplete脊凰,isEquivalentTo等方法。我們這里最終返回的Request就是后面說的==SingleRequest==對象。
** 3.2.1 說這個(gè)buildRequest方法之前狸涌,解釋一下requestManager.track這個(gè)方法**
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)建了一個(gè)targets集合。這個(gè)類的作用就是將所有的target添加到集合帕胆,并在生命周期變化時(shí)管理它朝捆。
public final class TargetTracker implements LifecycleListener {
// targets是一個(gè)具有映射關(guān)系的set無序集合。key就是target懒豹。
//WeakHashMap也是一種hashmap芙盘,特點(diǎn)就是它的key是弱鍵,當(dāng)key不使用的時(shí)候可以被回收脸秽。
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這個(gè)類:
==RequestTracker是個(gè)管理request的工具類==
public class RequestTracker {
//將所有的request放入到一個(gè)有映射關(guān)系的set集合中驮樊,用來控制reuqest的行為
private final Set<Request> requests =Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
//排隊(duì)等待執(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),最后返回的就是這個(gè)SingleRequest對象
return SingleRequest.obtain(
context,
glideContext,
requestLock,
model,
transcodeClass,
requestOptions,
overrideWidth,
overrideHeight,
priority,
target,
targetListener,
requestListeners,
requestCoordinator,
glideContext.getEngine(),
transitionOptions.getTransitionFactory(),
callbackExecutor);
}
obtainRequest()方法來獲取一個(gè)Request對象.obtainRequest()方法有調(diào)用了SingleRequest.obtain方法断国,傳入之前配置好的參數(shù)各種參數(shù)贤姆。這些參數(shù)其實(shí)都是組裝到Request對象中了。
3.3.2 SingleRequest
==再看下SingleRequest類==稳衬,SingleRequest.obtain的之后就是SingleRequest的初始化操作并且參數(shù)賦值霞捡。這個(gè)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)界面渲染完成時(shí)獲取view的大斜绦拧( ViewTreeObserver observer = view.getViewTreeObserver();)
//還是會(huì)調(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、弱引用緩存:使用弱引用,來緩存圖片猖辫,圖片被回收后酥泞,會(huì)保存到內(nèi)存緩存中。
2住册、內(nèi)存緩存LruCache:(默認(rèn)是在創(chuàng)建Glide的時(shí)候創(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ù)這個(gè)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有個(gè)抽象方法就是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 {
//這個(gè)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是保存活動(dòng)資源的一個(gè)類,它里面有個(gè)內(nèi)部類ResourceWeakReference,這個(gè)ResourceWeakReference繼承WeakReference望艺。
這個(gè)ActiveResources里面有一個(gè)value是ResourceWeakReference類型的map苛秕,它主要保存的就是活動(dòng)的資源,我們叫他弱應(yīng)用緩存找默。緩存是先從弱應(yīng)用緩存中查找艇劫,沒找到再去內(nèi)存緩存中查找。
再看下這個(gè)弱應(yīng)用緩存是什么時(shí)候存進(jìn)去的惩激?
//1店煞、弱應(yīng)用緩存沒找到,就會(huì)去內(nèi)存緩存找风钻,內(nèi)存緩存找到后保存到弱應(yīng)用緩存
private EngineResource<?> loadFromCache(Key key) {
EngineResource<?> cached = getEngineResourceFromCache(key);
if (cached != null) {
cached.acquire();
//這個(gè)方法就是往弱應(yīng)用緩存map中存數(shù)據(jù)
activeResources.activate(key, cached);
}
return cached;
}
//2顷蟀、當(dāng)內(nèi)存緩存中都沒有找到,那就去磁盤中找骡技,在沒有的就去網(wǎng)絡(luò)獲取鸣个,這時(shí)候獲取到資源并且展示完成后再存到弱應(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í)行一個(gè)新的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ù)涛舍。
//這個(gè)任務(wù),會(huì)現(xiàn)在磁盤緩存中查找右遭,因?yàn)榇疟P讀取耗時(shí)較大做盅,所以放在任務(wù)線程中
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
//如果current不等于null,說明這個(gè)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)建一個(gè)新的engineJob對象吹榴,它里面有很多Executor,用來加載異步圖片
EngineJob<R> engineJob =
engineJobFactory.build(
key,
isMemoryCacheable,
useUnlimitedSourceExecutorPool,
useAnimationPool,
onlyRetrieveFromCache);
//創(chuàng)建一個(gè)解碼工作的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)远剩,這個(gè)接口回調(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ù)了兩個(gè)map,一個(gè)新job骇窍,一個(gè)緩存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ù)其他的條件判斷使用哪個(gè)Executor
//ture:有緩存痢掠,則使用磁盤緩存線程池驱犹。否則返回?cái)?shù)據(jù)源線程池;
GlideExecutor executor =
decodeJob.willDecodeFromCache() ? diskCacheExecutor : getActiveSourceExecutor();
//執(zhí)行decodeJob的run方法
executor.execute(decodeJob);
}
通過上面start()方法知道是去磁盤取還是網(wǎng)絡(luò)獲取足画,對應(yīng)執(zhí)行器再去執(zhí)行這個(gè)decodeJob雄驹。
3.8 DecodeJob
這個(gè)類負(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 獲取下一個(gè)階段從哪里獲取數(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),判斷具體有哪個(gè)類執(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ù)源緩存任意一個(gè)沒有取到緩存胁黑,則就去網(wǎng)絡(luò)請求數(shù)據(jù)。
該類繼承了DataFetcherGenerator州泊, 這是一個(gè)數(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);
}
}
這三個(gè)數(shù)據(jù)抓取執(zhí)行器分別是:磁盤資源緩存執(zhí)行器、磁盤數(shù)據(jù)源執(zhí)行器遥皂、網(wǎng)絡(luò)元數(shù)據(jù)執(zhí)行器力喷;通過這個(gè)stage去選擇哪一個(gè)執(zhí)行器。
3.8.4 DecodeJob.runGenerators()
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
//判斷邏輯主要看startNext方法演训,這個(gè)方法回去執(zhí)行不同執(zhí)行器的startNext方法弟孟。
// 返回值是個(gè)布爾值,如果返回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ù)加載集合中, 獲取一個(gè)數(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++) {
//此時(shí)的model為url的string格式吊说,返回該其中一個(gè)實(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ò)請求返回?cái)?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í)候數(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ù)
這個(gè)回調(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 是一個(gè)泛型尊沸,本例中是 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贤惯、獲取一個(gè)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);
//此時(shí)的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);
// 這個(gè)方法是回調(diào)到Decodejob.onResourceDecoded ,作用是調(diào)用RequestOptions中的Transform處理圖片,然后將ResourceCache的Key和Encode準(zhǔn)備好(放在變量 deferEncoderManager中)叹俏,最后將這個(gè)源數(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是一個(gè)ResourceDecoder接口(資源解碼器)粘驰,根據(jù)不同的DataType和ResourceType它會(huì)有不同的實(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方法,
里面有個(gè)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)存抖動(dòng)
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();
//計(jì)算縮放比例粹舵,結(jié)果會(huì)體現(xiàn)在options參數(shù)中
calculateScaling(
imageType,
imageReader,
callbacks,
bitmapPool,
downsampleStrategy,
degreesToRotate,
sourceWidth,
sourceHeight,
targetWidth,
targetHeight,
options);
calculateConfig(
imageReader,
decodeFormat,
isHardwareConfigAllowed,
isExifOrientationRequired,
options,
targetWidth,
targetHeight);
//計(jì)算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.
//下面的判斷,來計(jì)算是否在BitmapPool中 是否有bitmap可以被復(fù)用眼滤,如果有就把bitmap 設(shè)置到options.inBitmap巴席,
//這樣在根據(jù)options 去解析生成bitmap的時(shí)候,就不需要再次分配內(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ù)會(huì)在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時(shí)蔫仙,調(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();
//這個(gè)callback 就是 EngineJob對象,是在創(chuàng)建Decodejob的時(shí)候傳遞進(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) {
//遍歷每一個(gè)回調(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 時(shí)竿裂,創(chuàng)建的
target.onResourceReady(result, animation);
}
} finally {
isCallingCallbacks = false;
}
notifyLoadSuccess();
}
ImageViewTarget的onResourceReady方法玉吁,ImageViewTarget是一個(gè)抽象類,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)哪里有錯(cuò)誤给赞,煩請指出~~~加油,奧利蓋~~~
至此矫户,完結(jié)...