錦囊篇|一文摸懂Glide
前言
和之前的文章會(huì)有一定的不同,這主要是因?yàn)?code style="font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:#e46918;background-color:#efefef;font-size:.875em;">Glide自身的源碼量導(dǎo)致的問(wèn)題,因?yàn)槲沂亲詈髮?xiě)的前言,你會(huì)發(fā)現(xiàn)在文章剛開(kāi)始時(shí)會(huì)代碼復(fù)制的比較完全,后面就比較零散,而且一部分我直接用自己話去進(jìn)行了表述。如果真的要看懂,建議還是對(duì)著Glide的源碼進(jìn)行查看,這樣會(huì)幫助你更好去理解GLide的它的實(shí)現(xiàn)流程。
(1)資源引入
repositories {
mavenCentral()
google()
}
dependencies {
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}
(2)方法使用
// 實(shí)現(xiàn)單張圖片加載
@Override public void onCreate(Bundle savedInstanceState) {
ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
// 如果是最新版的系統(tǒng)是不允許http來(lái)進(jìn)行請(qǐng)求的
// 去百度隨便拿一張圖片的地址來(lái)改一下就好了
Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}
// 實(shí)現(xiàn)圖片列表加載
@Override public View getView(int position, View recycled, ViewGroup container) {
final ImageView myImageView;
if (recycled == null) {
myImageView = (ImageView) inflater.inflate(R.layout.my_image_view, container, false);
} else {
myImageView = (ImageView) recycled;
}
String url = myUrls.get(position);
Glide
.with(myFragment)
.load(url)
.centerCrop()
.placeholder(R.drawable.loading_spinner)
.into(myImageView);
return myImageView;
}
源碼分析在源碼使用中,其實(shí)基礎(chǔ)的在上面的使用方法中已經(jīng)講述到了,一共可以分為三個(gè)步驟:
- with(Context)
- load(ImageURL)
- into(ImageView)
我們的分析流程也將圍繞這三個(gè)函數(shù)來(lái)進(jìn)行展開(kāi)。
with(Context)
@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);
}
@SuppressWarnings("deprecation")
@Deprecated
@NonNull
public static RequestManager with(@NonNull android.app.Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
@NonNull
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
悄咪咪數(shù)了數(shù),Oh my Gosh?。?! 竟然高達(dá)有6個(gè)重載方法。不過(guò)呢想必你也發(fā)現(xiàn)這些方法都直接調(diào)用了getRetriever().get()的方法,那目的就非常明顯了,我們進(jìn)到這個(gè)方法去一探究竟了。
@NonNull
private static RequestManagerRetriever getRetriever(@Nullable Context context) {
return Glide.get(context).getRequestManagerRetriever(); // 1 -->
}
@NonNull
public static Glide get(@NonNull Context context) {
if (glide == null) {
// 使用了context.getApplicationContext()是為了防止內(nèi)存泄漏的發(fā)生
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
// 對(duì)glide整體地進(jìn)行初始化
// 其中就包含了對(duì)RequestManagerRetriever的初始化流程
// 代碼量比較大就不做介紹了
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
既然是一堆的初始化操作,最后我們的目標(biāo)又是RequestManagerRetriever這個(gè)類(lèi),那自然是有必要對(duì)這個(gè)類(lèi)進(jìn)行探究的。
public class RequestManagerRetriever implements Handler.Callback {
public RequestManagerRetriever(@Nullable RequestManagerFactory factory) {
this.factory = factory != null ? factory : DEFAULT_FACTORY;
handler = new Handler(Looper.getMainLooper(), this /* Callback */);
}
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);
}
};
// getRetriever()的get()方法
// 對(duì)標(biāo)上面的6個(gè)重載方法的調(diào)用,這里只取其一
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
// 如果當(dāng)前的線程是在后臺(tái)線程中,則進(jìn)入
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext()); // 1-->
} else {
assertNotDestroyed(activity);
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, /*parentHint=*/ null, isActivityVisible(activity)); // 2 -->
}
}
}
(1)通過(guò)構(gòu)造函數(shù)我們能夠猜測(cè)的內(nèi)容是通信的工具是Handler,而Looper使用的是MainLooper也就是主線程的,那說(shuō)明最后異步通信也就直接扔到主線程完成了。
(2)通過(guò)get()函數(shù),可以發(fā)現(xiàn)其實(shí)分為兩個(gè)部分。一是再一層的get()方法;二是supportFragmentGet()或者是FragmentGet()方法。
他們最后的任務(wù)都是為了創(chuàng)建出一個(gè)RequestManager,但是我們得關(guān)注一下它的創(chuàng)建方式。
get()
對(duì)于這個(gè)方法而言就是對(duì)context的判定是否為Application,然后給出相應(yīng)的結(jié)果。
(1)不是Application且是在主線程中時(shí)
if (Util.isOnMainThread() && !(context instanceof Application)) {
if (context instanceof FragmentActivity) {
return get((FragmentActivity) context);
} else if (context instanceof Activity) {
return get((Activity) context);
} else if (context instanceof ContextWrapper
&& ((ContextWrapper) context).getBaseContext().getApplicationContext() != null) {
return get(((ContextWrapper) context).getBaseContext());
}
}
而他們的歸宿,最后還是回到我們上方的重載方法。
(2)是Application或是不再主線程時(shí)
getApplicationManager(context); // 1 -->
// 使用DCL的方式來(lái)創(chuàng)建了單例
@NonNull
private RequestManager getApplicationManager(@NonNull Context context) {
// Either an application context or we're on a background thread.
if (applicationManager == null) {
synchronized (this) {
if (applicationManager == null) {
Glide glide = Glide.get(context.getApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(), // 2
new EmptyRequestManagerTreeNode(),
context.getApplicationContext());
}
}
}
return applicationManager;
}
通過(guò)工廠來(lái)自建了一個(gè)RequestManager,注釋2處他直接使用了ApplicationLifecycle原因是因?yàn)槟承┣闆r下會(huì)接受不到生命周期的事件,這里是做的強(qiáng)制性的操作是為了生命周期變化時(shí)能夠正常相應(yīng)。
FragmentGet()
瞟了一下,這是要一個(gè)廢棄的方法了,但是和supportFragmentGet()的方法相比其實(shí)也差不太多。
private RequestManager fragmentGet(
@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible); // 1 -->
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
// 將requestManager和Fragment相掛鉤
// 用以完成生命周期的監(jiān)聽(tīng)
current.setRequestManager(requestManager);
}
return requestManager;
}
// 1 -->
// 獲取對(duì)應(yīng)的Fragment
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
// 尋找的方式是通過(guò)設(shè)置的TAG
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
// 先去等待隊(duì)列中進(jìn)行查詢
// 這一步的作用是防止Fragment的重復(fù)添加
// 因?yàn)樘砑拥腇ragment的所謂的生命周期有一定的延時(shí)性
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
// 如果等待隊(duì)列創(chuàng)建一個(gè)新的TAG
if (current == null) {
current = new RequestManagerFragment();
current.setParentFragmentHint(parentHint);
if (isParentVisible) {
current.getGlideLifecycle().onStart();
}
pendingRequestManagerFragments.put(fm, current);
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).sendToTarget();
}
}
return current;
}
總結(jié)
- 初始化
Glide的同時(shí)在內(nèi)部完成了RequestManagerRetriever的創(chuàng)建 - 獲取到的
RequestManagerRetriever調(diào)用get()方法,獲取到RequestManager,獲取方式分為以下兩種:
Context為Application時(shí), 通過(guò)getApplicationManager()方法創(chuàng)建RequestManager完成,將生命周期的監(jiān)聽(tīng)與Application強(qiáng)制綁定用于接收。Context不為Application時(shí), 通過(guò)supportFragmentGet()方法創(chuàng)建RequestManager完成,生命周期的監(jiān)聽(tīng)是與Fragment進(jìn)行綁定實(shí)現(xiàn)。
創(chuàng)建對(duì)應(yīng)TAG的一個(gè)非常直接的好處,我們的圖片像RecyclerView會(huì)放置中不容易出現(xiàn)錯(cuò)位的現(xiàn)象。
load(ImageURL)
總體來(lái)說(shuō)上面的就是一個(gè)初始化和必要變量獲取的操作,那接下從函數(shù)方法來(lái)看我們似乎是要去獲得的圖片了呢。
public RequestBuilder load(@Nullable String string) {
return asDrawable().load(string); // 1 -->
}
注釋1處,我們通過(guò)觀察可以知道他最后會(huì)選擇將獲取的數(shù)據(jù)轉(zhuǎn)化變成一個(gè)Drawable的類(lèi)然后再在我們對(duì)應(yīng)的ImageView上來(lái)進(jìn)行顯示。那我們就對(duì)asDrawable()先進(jìn)行一段源碼的分析。
// asDrawable()不斷深入能發(fā)現(xiàn)調(diào)用到的函數(shù)
// 是完成一個(gè)類(lèi)RequestBuilder的對(duì)象創(chuàng)建
public RequestBuilder as(
@NonNull Class resourceClass) { // Drawable.class
return new RequestBuilder<>(glide, this, resourceClass, context);
}
那接下來(lái)的問(wèn)題就要進(jìn)入到這個(gè)類(lèi)中,因?yàn)樵谇懊嫖覀兊奶剿髌鋵?shí)算是并沒(méi)有什么收獲的,而如果只是創(chuàng)建一個(gè)類(lèi)顯然是不會(huì)讓這句話顯得這么重要,那關(guān)鍵點(diǎn)一定會(huì)出現(xiàn)在這個(gè)類(lèi)的構(gòu)造中了。
protected RequestBuilder(
@NonNull Glide glide,
RequestManager requestManager,
Class 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()); // 1 -->
// 這段代碼過(guò)長(zhǎng),不做展示,它的主要任務(wù)就是一些策略開(kāi)關(guān)
// 各種選項(xiàng)的開(kāi)啟裝置,比如錯(cuò)誤提示、優(yōu)先級(jí)、磁盤(pán)緩存策略、固定寬高等等
apply(requestManager.getDefaultRequestOptions());
}
// 1-->
// 從某種意義上講就是對(duì)生命周期的監(jiān)聽(tīng)
private void initRequestListeners(List> requestListeners) {
for (RequestListener而如果回到load(string)方法。
private RequestBuilder loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
他最后的差事也就是將URI的值放到了model這個(gè)變量中,那整個(gè)load()函數(shù)作用其實(shí)最后只是創(chuàng)建了一個(gè)RequestBuilder的事例,那最后的獲取和加載工作肯定是在into()函數(shù)中才進(jìn)行了操作的。
into(ImageView)
public ViewTarget into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// 通過(guò)scaleType,對(duì)圖片的屬性進(jìn)行設(shè)定
switch (view.getScaleType()) {
case CENTER_CROP:
// 。。。。。。
default:
// Do nothing.
}
}
// 正式將圖片數(shù)據(jù)塞入
// 1 -->
return into(
// 2 -->
glideContext.buildImageViewTarget(view, transcodeClass), // 深度調(diào)用可以知道也就是將View進(jìn)行了賦值
/*targetListener=*/ null,
requestOptions,
// 能夠看到線程池的影子,后面的圖片的獲取和處理我們猜測(cè)就是通過(guò)池來(lái)進(jìn)行處理
Executors.mainThreadExecutor());
}
// 1 --> 將數(shù)據(jù)塞入
private > Y into(
@NonNull Y target,
@Nullable RequestListener targetListener,
BaseRequestOptions> options,
Executor callbackExecutor) {
// 正常情況構(gòu)建SingleRequest的請(qǐng)求
// 因?yàn)閠humbnail一般需要額外的需求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
// 當(dāng)前請(qǐng)求和最新的一樣
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
// 如果請(qǐng)求完成,重新啟動(dòng)會(huì)保證結(jié)果送達(dá)并觸動(dòng)目標(biāo)
// 如果請(qǐng)求失敗,會(huì)給出機(jī)會(huì)去再次完成
// 如果請(qǐng)求正在運(yùn)行,不會(huì)打斷
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request); // 置換最新的請(qǐng)求
requestManager.track(target, request); // 3 -->
return target;
}
下面的內(nèi)容將主要對(duì)上述代碼中的注釋2和注釋3進(jìn)行講解。
glideContext.buildImageViewTarget(view, transcodeClass)
從字面意思,相比你也能夠進(jìn)行理解了,就是要構(gòu)建一個(gè)存放的目標(biāo)。
@NonNull
public ViewTarget buildImageViewTarget(
@NonNull ImageView imageView, @NonNull Class transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass); // 1 -->
}
// 1-->
// 根據(jù)不同的數(shù)據(jù)類(lèi)型選擇存儲(chǔ)是以Drawable還是Bitmap構(gòu)建
public ViewTarget buildTarget(
@NonNull ImageView view, @NonNull Class clazz) {
if (Bitmap.class.equals(clazz)) {
// 以Bitmap構(gòu)建
return (ViewTarget) new BitmapImageViewTarget(view); // 2-->
} else if (Drawable.class.isAssignableFrom(clazz)) {
// 以Drawable構(gòu)建
return (ViewTarget) new DrawableImageViewTarget(view); // 2 -->
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
// 2-->
// 兩個(gè)注釋最后深度調(diào)用之后都會(huì)調(diào)用到這段代碼
// 如果單看這段代碼的時(shí)候其實(shí)
public ViewTarget(@NonNull T view) {
this.view = Preconditions.checkNotNull(view);
// 如果只看這個(gè)構(gòu)造函數(shù),確實(shí)沒(méi)什么東西
// 不行你可以直接看注釋3的代碼處
sizeDeterminer = new SizeDeterminer(view); // 3 -->
}
// 非常簡(jiǎn)單的就只是對(duì)view進(jìn)行了一個(gè)賦值操作
SizeDeterminer(@NonNull View view) {
this.view = view;
}
那如果就只有上面那么一點(diǎn)不就完了??其實(shí)并不,如果你觀察了一下DrawableImageViewTarget和BitmapImageViewTarget的其他方法,能發(fā)現(xiàn)這樣的一個(gè)特征。
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
沒(méi)錯(cuò)!! 賦值操作,這個(gè)操作說(shuō)明最后其實(shí)的結(jié)束點(diǎn)肯定是在這里的,而調(diào)用他的函數(shù)最后也就是onResourceReady()這個(gè)方法,也就意味著圖片獲取成功了,不過(guò)呢這個(gè)請(qǐng)求完成肯定是和數(shù)據(jù)的獲取相互關(guān)聯(lián)的,也就是下面部分的內(nèi)容了。
requestManager.track(target, request)
// 以同步的方式完成數(shù)據(jù)的請(qǐng)求
synchronized void track(@NonNull Target> target, @NonNull Request request) {
targetTracker.track(target); // 對(duì)當(dāng)前的目標(biāo)的生命周期有一個(gè)追蹤
requestTracker.runRequest(request); // 2 --> 執(zhí)行操作正式開(kāi)啟
}
// 2 -->
public void runRequest(@NonNull Request request) {
requests.add(request);
// 會(huì)對(duì)當(dāng)前的所有請(qǐng)求做一個(gè)判斷處理
// 會(huì)根據(jù)當(dāng)前的狀態(tài)確定是否要進(jìn)行數(shù)據(jù)加載的操作
// 一般來(lái)說(shuō)對(duì)應(yīng)的就是生命周期
if (!isPaused) {
request.begin();
} else {
request.clear();
pendingRequests.add(request);
}
}
那上面一段代碼說(shuō)明我們正常運(yùn)行的時(shí)候,網(wǎng)絡(luò)傳輸?shù)牟僮骺隙ㄊ且呀?jīng)在正常運(yùn)行了的,而其實(shí)正常沒(méi)有設(shè)置時(shí)調(diào)用的會(huì)是SingleRequest的類(lèi),不多逼逼,瞅瞅它的begin()方法有什么特殊之處了。
public void begin() {
synchronized (requestLock) {
// 。。。。。
// 如果正在運(yùn)行就拋出異常
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
// 從緩存中直接拿出數(shù)據(jù)
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
// ==============重中之重==============
// 因?yàn)樵谏鲜鑫恼轮兄v到過(guò)了圖片的大小問(wèn)題
// 在Glide中這里就是給出解決方案的地方,兩種方案:
// 1. 給出了固定長(zhǎng)寬
// 2. 沒(méi)有設(shè)置時(shí)
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
// 使用一個(gè)占位符先頂替
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
}
}
那接下來(lái)要講述的內(nèi)容就應(yīng)該是他的一些大小設(shè)置問(wèn)題了,Glide到底是用什么樣的方式完成大小的設(shè)置的呢?
onSizeReady(overrideWidth, overrideHeight)
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
// .....
status = Status.RUNNING;
// 對(duì)長(zhǎng)寬重新進(jìn)行預(yù)估
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
loadStatus =
engine.load(各種參數(shù));
// .....
}
}
通過(guò)觀察對(duì)onSizeReady()函數(shù)發(fā)現(xiàn),他使用的方案其實(shí)又是一個(gè)名叫做engine.load()的方式。
public LoadStatus load(各種參數(shù)) {
EngineResource> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(各種參數(shù));
}
}
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
上述是我省略過(guò)后的代碼,他表達(dá)意思其實(shí)非常之簡(jiǎn)單:
(1)內(nèi)存里有數(shù)據(jù),你就從我內(nèi)存里拿。
(2)內(nèi)存里沒(méi)數(shù)據(jù),那你就自己創(chuàng)建一個(gè)。
這樣想來(lái),問(wèn)題又要往下繼續(xù)延伸了,正常來(lái)說(shuō)我們沒(méi)有數(shù)據(jù)啊,那就要去調(diào)用這個(gè)waitForExistingOrStartNewJob()方法,來(lái)完成圖片數(shù)據(jù)的獲取了。
private LoadStatus waitForExistingOrStartNewJob(各種參數(shù)) {
EngineJob> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
return new LoadStatus(cb, current);
}
EngineJob engineJob =
engineJobFactory.build(各種參數(shù));
DecodeJob decodeJob =
decodeJobFactory.build(各種參數(shù));
jobs.put(key, engineJob); // 對(duì)當(dāng)前驅(qū)動(dòng)工作進(jìn)行緩存操作
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob); // 開(kāi)啟圖片獲取工作
return new LoadStatus(cb, engineJob);
}
能夠注意到有出現(xiàn)兩個(gè)新的類(lèi)EngineJob和DecodeJob,轉(zhuǎn)換成中文去理解就是工作驅(qū)動(dòng)器和解碼工作,并且EngineJob內(nèi)部與線程池搭噶,最后肯定用于完成最后的圖片獲取工作,而DecodeJob作為被運(yùn)行的工作,處理邏輯就應(yīng)該在其之中。
public void run() {
DataFetcher> localFetcher = currentFetcher;
try {
// .....
runWrapped(); // 1 -->
} catch (Exception e) {
// .....
} finally {
// .....
}
}
// 1 -->
private void runWrapped() {
switch (runReason) {
case INITIALIZE:
// 獲取 Stage.INITIALIZE 的下一步操作,也就是選擇三種方案
// 1. 資源緩存:ResourceCacheGenerator
// 2. 數(shù)據(jù)緩存:DataCacheGenerator
// 3. 網(wǎng)絡(luò)資源:SourceGenerator
stage = getNextStage(Stage.INITIALIZE);
currentGenerator = getNextGenerator();
runGenerators();
break;
case SWITCH_TO_SOURCE_SERVICE:
runGenerators();
break;
case DECODE_DATA:
decodeFromRetrievedData();
break;
default:
throw new IllegalStateException("Unrecognized run reason: " + runReason);
}
}
其實(shí)上述內(nèi)容中已經(jīng)開(kāi)始講述到我們常見(jiàn)的三大緩存了,也就是網(wǎng)絡(luò)緩存、磁盤(pán)緩存和內(nèi)存緩存,這段代碼中其實(shí)已經(jīng)開(kāi)始涉及網(wǎng)絡(luò)緩存和磁盤(pán)緩存了。
SourceGenerator:關(guān)于網(wǎng)絡(luò)緩存
private void runGenerators() {
currentThread = Thread.currentThread();
startFetchTime = LogTime.getLogTime();
boolean isStarted = false;
while (!isCancelled
&& currentGenerator != null
&& !(isStarted = currentGenerator.startNext())) { // 1 -->
stage = getNextStage(stage);
currentGenerator = getNextGenerator();
// 只對(duì)Source這個(gè)枚舉類(lèi)型相應(yīng)
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// 已完成就通知失敗
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
// 1-->
public boolean startNext() {
// 需要數(shù)據(jù)有緩存才行
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
// 從映射表找出能夠?qū)?yīng)上的圖片類(lèi)型的ModelLoader
loadData = helper.getLoadData().get(loadDataListIndex++);
if (loadData != null
&& (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
|| helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
started = true;
// 完成數(shù)據(jù)的加載
startNextLoad(loadData);
}
}
return started;
}
針對(duì)注釋1進(jìn)行探討,這里的話,我們就盡量不放代碼查看了,因?yàn)榭戳诉@么多代碼,你肯定也累了。其實(shí)你能夠猜測(cè)到它的下一步是網(wǎng)絡(luò)請(qǐng)求,那如果獲取成功了,是要直接進(jìn)行圖片數(shù)據(jù)的顯示嗎?那三次緩存應(yīng)該在什么時(shí)機(jī)進(jìn)行操作呢?因?yàn)榇a量的原因,這里我們用圖來(lái)展示流程。

從圖中可以知道,其實(shí)從網(wǎng)絡(luò)獲取的資源最后還是要被放到磁盤(pán)中進(jìn)行緩存的,而磁盤(pán)緩存成功之后,接下來(lái)要干的事情就是要去通知View把獲取的數(shù)據(jù)進(jìn)行解碼。這里你是否有一定的疑問(wèn)了?
你沒(méi)有聽(tīng)錯(cuò),就是解碼,如果你去各個(gè)官方查看圖片的時(shí)候,很多給的都是后期重新被編碼過(guò)的數(shù)據(jù),本身數(shù)據(jù)其實(shí)并不能夠在直接運(yùn)行的,而解碼就是讓圖片正式可視化的必經(jīng)之路,也就是DecodeJob的本質(zhì)工作了,對(duì)應(yīng)的函數(shù)就是decodeFromRetrievedData()方法,把磁盤(pán)中拷貝出來(lái)的數(shù)據(jù)要進(jìn)行解碼操作。
private void decodeFromRetrievedData() {
Resource resource = null;
// 將網(wǎng)絡(luò)獲取的數(shù)據(jù)進(jìn)行解碼操作
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource); // 1 -->
} catch (GlideException e) {
}
// 解碼完成,發(fā)出通知
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource); // 2-->
} else {
runGenerators();
}
}
你能夠發(fā)現(xiàn)我在這段代碼中打了兩個(gè)注釋?zhuān)鋵?shí)對(duì)應(yīng)的就是兩大操作解碼完成,通知可以顯示了。
decodeFromData(currentFetcher, currentData, currentDataSource);
下面會(huì)給出一段很長(zhǎng)的深度調(diào)用代碼。
(1)resource = decodeFromData(currentFetcher, currentData, currentDataSource);
(2)Resource result = decodeFromFetcher(data, dataSource);
(3)return path.load(
rewinder, options, width, height, new DecodeCallback(dataSource));
(4)return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
(5)result = path.decode(rewinder, width, height, options, decodeCallback);
(6)
public Resource decode(
DataRewinder rewinder,
int width,
int height,
@NonNull Options options,
DecodeCallback callback)
throws GlideException {
// 這里會(huì)有很多轉(zhuǎn)化的方法,一般來(lái)說(shuō)對(duì)圖片最常見(jiàn)的就是轉(zhuǎn)成Bitmap
Resource decoded = decodeResource(rewinder, width, height, options);
Resource transformed = callback.onResourceDecoded(decoded);
return transcoder.transcode(transformed, options);
}
在decode()這個(gè)函數(shù)其實(shí)做了三件事:
decodeResource將原始數(shù)據(jù)轉(zhuǎn)換成我們?cè)紙D片的過(guò)程;callback.onResourceDecoded()是當(dāng)?shù)玫搅嗽紙D片之后對(duì)圖片繼續(xù)處理過(guò)程;transcoder.transcode()會(huì)使用BitmapDrawableTranscoder進(jìn)行再包裝
decodeResource中可以轉(zhuǎn)化的部分解碼器
那這個(gè)時(shí)候你就正式拿到了一張圖片了,那下一步還需要干嘛???顯示?。。?!廢了這么大周折,還不趕緊拿去顯示,不是做了一大堆無(wú)用功嘛?
notifyEncodeAndRelease(resource, currentDataSource);
只看少量代碼來(lái)完成這項(xiàng)工作
(1)notifyComplete(result, dataSource);
(2)
private void notifyComplete(Resource resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
你是否有注意到這樣的問(wèn)題,onResourceReady()是不是有點(diǎn)眼熟,在很上面的glideContext.buildImageViewTarget(view, transcodeClass),也就是構(gòu)建放置的目標(biāo)中我們就已經(jīng)講到過(guò)這個(gè)方法了,最后會(huì)通過(guò)一個(gè)set()的方法來(lái)將數(shù)據(jù)進(jìn)行放置。
那基本上來(lái)說(shuō),上面就是一個(gè)比較詳細(xì)的Glide的源碼分析,因?yàn)榇a是在太多了,所以我這里刪去了很多。
其實(shí)你會(huì)發(fā)現(xiàn)我并沒(méi)有正式講完三級(jí)緩存,還差一個(gè)內(nèi)存緩存沒(méi)講不是?
其實(shí)這是一個(gè)很早就被用到的方法,他對(duì)應(yīng)的位置就在SingleRequest被調(diào)用了OnSizeReady()方法的時(shí)候有個(gè)engine.load(),里面就包含了第三級(jí)緩存內(nèi)存緩存,里面對(duì)應(yīng)的是這樣的一段代碼memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);以及他深度調(diào)用后的EngineResource> active = loadFromActiveResources(key);從活躍的的資源數(shù)據(jù)中進(jìn)行尋找。同樣是一個(gè)非常簡(jiǎn)單的實(shí)現(xiàn)手法。
final Map activeEngineResources = new HashMap<>();
就是通過(guò)一個(gè)Map對(duì)數(shù)據(jù)進(jìn)行了保存,這樣從復(fù)用的角度上來(lái)看就被比較好的繼承了。
但如果不是活躍資源數(shù)據(jù)呢?
不要著急,還有一些數(shù)據(jù)還會(huì)在cache的變量中被保存著,這個(gè)方法里就是用了我們經(jīng)常會(huì)提及到的LRUCache的一個(gè)淘汰算法,這里的詳細(xì)請(qǐng)查看我的另外一篇文章:Glide都在用的LruCache,你學(xué)會(huì)了嗎?。
