和以前的文章會有必定的不一樣,這主要是由於Glide
自身的源碼量致使的問題,由於我是最後寫的前言,你會發如今文章剛開始時會代碼複製的比較徹底,後面就比較零散,並且一部分我直接用本身話去進行了表述。若是真的要看懂,建議仍是對着Glide
的源碼進行查看,這樣會幫助你更好去理解GLide
的它的實現流程。java
(1)資源引入android
repositories {
mavenCentral()
google()
}
dependencies {
implementation 'com.github.bumptech.glide:glide:4.11.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'
}
複製代碼
(2)方法使用git
// 實現單張圖片加載
@Override public void onCreate(Bundle savedInstanceState) {
ImageView imageView = (ImageView) findViewById(R.id.my_image_view);
// 若是是最新版的系統是不容許http來進行請求的
// 去百度隨便拿一張圖片的地址來改一下就行了
Glide.with(this).load("http://goo.gl/gEgYUd").into(imageView);
}
// 實現圖片列表加載
@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;
}
複製代碼
在源碼使用中,其實基礎的在上面的使用方法中已經講述到了,一共能夠分爲三個步驟:github
咱們的分析流程也將圍繞這三個函數來進行展開。算法
@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);
}
複製代碼
悄咪咪數了數,Oh my Gosh!!! 居然高達有6個重載方法。不過呢想必你也發現這些方法都直接調用了getRetriever().get()
的方法,那目的就很是明顯了,咱們進到這個方法去一探究竟了。緩存
@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()是爲了防止內存泄漏的發生
GeneratedAppGlideModule annotationGeneratedModule =
getAnnotationGeneratedGlideModules(context.getApplicationContext());
synchronized (Glide.class) {
if (glide == null) {
// 對glide總體地進行初始化
// 其中就包含了對RequestManagerRetriever的初始化流程
// 代碼量比較大就不作介紹了
checkAndInitializeGlide(context, annotationGeneratedModule);
}
}
}
return glide;
}
複製代碼
既然是一堆的初始化操做,最後咱們的目標又是RequestManagerRetriever
這個類,那天然是有必要對這個類進行探究的。網絡
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()方法
// 對標上面的6個重載方法的調用,這裏只取其一
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
// 若是當前的線程是在後臺線程中,則進入
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)經過構造函數咱們可以猜想的內容是通訊的工具是Handler
,而Looper
使用的是MainLooper
也就是主線程的,那說明最後異步通訊也就直接扔到主線程完成了。app
(2)經過get()
函數,能夠發現其實分爲兩個部分。一是再一層的get()
方法;二是supportFragmentGet()
或者是FragmentGet()
方法。異步
他們最後的任務都是爲了建立出一個RequestManager
,可是咱們得關注一下它的建立方式。maven
get()
對於這個方法而言就是對context
的斷定是否爲Application
,而後給出相應的結果。
(1)不是Application
且是在主線程中時
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
或是再也不主線程時
getApplicationManager(context); // 1 -->
// 使用DCL的方式來建立了單例
@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;
}
複製代碼
經過工廠來自建了一個RequestManager
,註釋2處他直接使用了ApplicationLifecycle
緣由是由於某些狀況下會接受不到生命週期的事件,這裏是作的強制性的操做是爲了生命週期變化時可以正常相應。
FragmentGet()
瞟了一下,這是要一個廢棄的方法了,可是和supportFragmentGet()
的方法相比其實也差不太多。
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相掛鉤
// 用以完成生命週期的監聽
current.setRequestManager(requestManager);
}
return requestManager;
}
// 1 -->
// 獲取對應的Fragment
private RequestManagerFragment getRequestManagerFragment( @NonNull final android.app.FragmentManager fm, @Nullable android.app.Fragment parentHint, boolean isParentVisible) {
// 尋找的方式是經過設置的TAG
RequestManagerFragment current = (RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
// 先去等待隊列中進行查詢
// 這一步的做用是防止Fragment的重複添加
// 由於添加的Fragment的所謂的生命週期有必定的延時性
if (current == null) {
current = pendingRequestManagerFragments.get(fm);
// 若是等待隊列建立一個新的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;
}
複製代碼
總結
Glide
的同時在內部完成了RequestManagerRetriever
的建立RequestManagerRetriever
調用get()
方法,獲取到RequestManager
,獲取方式分爲如下兩種:
Context
爲Application
時, 經過getApplicationManager()
方法建立RequestManager
完成,將生命週期的監聽與Application
強制綁定用於接收。Context
不爲Application
時, 經過supportFragmentGet()
方法建立RequestManager
完成,生命週期的監聽是與Fragment
進行綁定實現。建立對應TAG的一個很是直接的好處,咱們的圖片像RecyclerView
會放置中不容易出現錯位的現象。
整體來講上面的就是一個初始化和必要變量獲取的操做,那接下從函數方法來看咱們彷佛是要去得到的圖片了呢。
public RequestBuilder<Drawable> load(@Nullable String string) {
return asDrawable().load(string); // 1 -->
}
複製代碼
註釋1處,咱們經過觀察能夠知道他最後會選擇將獲取的數據轉化變成一個Drawable
的類而後再在咱們對應的ImageView
上來進行顯示。那咱們就對asDrawable()
先進行一段源碼的分析。
// asDrawable()不斷深刻能發現調用到的函數
// 是完成一個類RequestBuilder的對象建立
public <ResourceType> RequestBuilder<ResourceType> as( @NonNull Class<ResourceType> resourceClass) { // Drawable.class
return new RequestBuilder<>(glide, this, resourceClass, context);
}
複製代碼
那接下來的問題就要進入到這個類中,由於在前面咱們的探索其實算是並無什麼收穫的,而若是隻是建立一個類顯然是不會讓這句話顯得這麼重要,那關鍵點必定會出如今這個類的構造中了。
protected RequestBuilder( @NonNull Glide glide, RequestManager requestManager, 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()); // 1 -->
// 這段代碼過長,不作展現,它的主要任務就是一些策略開關
// 各類選項的開啓裝置,好比錯誤提示、優先級、磁盤緩存策略、固定寬高等等
apply(requestManager.getDefaultRequestOptions());
}
// 1-->
// 從某種意義上講就是對生命週期的監聽
private void initRequestListeners(List<RequestListener<Object>> requestListeners) {
for (RequestListener<Object> listener : requestListeners) {
addListener((RequestListener<TranscodeType>) listener);
}
}
複製代碼
而若是回到load(string)
方法。
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
複製代碼
他最後的差事也就是將URI
的值放到了model
這個變量中,那整個load()
函數做用其實最後只是建立了一個RequestBuilder
的事例,那最後的獲取和加載工做確定是在into()
函數中才進行了操做的。
into(ImageView)
public ViewTarget<ImageView, TranscodeType> into(@NonNull ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
BaseRequestOptions<?> requestOptions = this;
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
// 經過scaleType,對圖片的屬性進行設定
switch (view.getScaleType()) {
case CENTER_CROP:
// 。。。。。。
default:
// Do nothing.
}
}
// 正式將圖片數據塞入
// 1 -->
return into(
// 2 -->
glideContext.buildImageViewTarget(view, transcodeClass), // 深度調用能夠知道也就是將View進行了賦值
/*targetListener=*/ null,
requestOptions,
// 可以看到線程池的影子,後面的圖片的獲取和處理咱們猜想就是經過池來進行處理
Executors.mainThreadExecutor());
}
// 1 --> 將數據塞入
private <Y extends Target<TranscodeType>> Y into( @NonNull Y target, @Nullable RequestListener<TranscodeType> targetListener, BaseRequestOptions<?> options, Executor callbackExecutor) {
// 正常狀況構建SingleRequest的請求
// 由於thumbnail通常須要額外的需求
Request request = buildRequest(target, targetListener, options, callbackExecutor);
Request previous = target.getRequest();
// 當前請求和最新的同樣
if (request.isEquivalentTo(previous)
&& !isSkipMemoryCacheWithCompletePreviousRequest(options, previous)) {
// 若是請求完成,從新啓動會保證結果送達並觸動目標
// 若是請求失敗,會給出機會去再次完成
// 若是請求正在運行,不會打斷
if (!Preconditions.checkNotNull(previous).isRunning()) {
previous.begin();
}
return target;
}
requestManager.clear(target);
target.setRequest(request); // 置換最新的請求
requestManager.track(target, request); // 3 -->
return target;
}
複製代碼
下面的內容將主要對上述代碼中的註釋2和註釋3進行講解。
glideContext.buildImageViewTarget(view, transcodeClass)
從字面意思,相比你也可以進行理解了,就是要構建一個存放的目標。
@NonNull
public <X> ViewTarget<ImageView, X> buildImageViewTarget( @NonNull ImageView imageView, @NonNull Class<X> transcodeClass) {
return imageViewTargetFactory.buildTarget(imageView, transcodeClass); // 1 -->
}
// 1-->
// 根據不一樣的數據類型選擇存儲是以Drawable仍是Bitmap構建
public <Z> ViewTarget<ImageView, Z> buildTarget( @NonNull ImageView view, @NonNull Class<Z> clazz) {
if (Bitmap.class.equals(clazz)) {
// 以Bitmap構建
return (ViewTarget<ImageView, Z>) new BitmapImageViewTarget(view); // 2-->
} else if (Drawable.class.isAssignableFrom(clazz)) {
// 以Drawable構建
return (ViewTarget<ImageView, Z>) new DrawableImageViewTarget(view); // 2 -->
} else {
throw new IllegalArgumentException(
"Unhandled class: " + clazz + ", try .as*(Class).transcode(ResourceTranscoder)");
}
}
// 2-->
// 兩個註釋最後深度調用以後都會調用到這段代碼
// 若是單看這段代碼的時候其實
public ViewTarget(@NonNull T view) {
this.view = Preconditions.checkNotNull(view);
// 若是隻看這個構造函數,確實沒什麼東西
// 不行你能夠直接看註釋3的代碼處
sizeDeterminer = new SizeDeterminer(view); // 3 -->
}
// 很是簡單的就只是對view進行了一個賦值操做
SizeDeterminer(@NonNull View view) {
this.view = view;
}
複製代碼
DrawableImageViewTarget
和
BitmapImageViewTarget
的其餘方法,能發現這樣的一個特徵。
protected void setResource(Bitmap resource) {
view.setImageBitmap(resource);
}
protected void setResource(@Nullable Drawable resource) {
view.setImageDrawable(resource);
}
複製代碼
沒錯!! 賦值操做,這個操做說明最後其實的結束點確定是在這裏的,而調用他的函數最後也就是onResourceReady()
這個方法,也就意味着圖片獲取成功了,不過呢這個請求完成確定是和數據的獲取相互關聯的,也就是下面部分的內容了。
requestManager.track(target, request)
// 以同步的方式完成數據的請求
synchronized void track(@NonNull Target<?> target, @NonNull Request request) {
targetTracker.track(target); // 對當前的目標的生命週期有一個追蹤
requestTracker.runRequest(request); // 2 --> 執行操做正式開啓
}
// 2 -->
public void runRequest(@NonNull Request request) {
requests.add(request);
// 會對當前的全部請求作一個判斷處理
// 會根據當前的狀態肯定是否要進行數據加載的操做
// 通常來講對應的就是生命週期
if (!isPaused) {
request.begin();
} else {
request.clear();
pendingRequests.add(request);
}
}
複製代碼
那上面一段代碼說明咱們正常運行的時候,網絡傳輸的操做確定是已經在正常運行了的,而其實正常沒有設置時調用的會是SingleRequest
的類,很少逼逼,瞅瞅它的begin()
方法有什麼特殊之處了。
public void begin() {
synchronized (requestLock) {
// 。。。。。
// 若是正在運行就拋出異常
if (status == Status.RUNNING) {
throw new IllegalArgumentException("Cannot restart a running request");
}
// 從緩存中直接拿出數據
if (status == Status.COMPLETE) {
onResourceReady(resource, DataSource.MEMORY_CACHE);
return;
}
// ==============重中之重==============
// 由於在上述文章中講到過了圖片的大小問題
// 在Glide中這裏就是給出解決方案的地方,兩種方案:
// 1. 給出了固定長寬
// 2. 沒有設置時
status = Status.WAITING_FOR_SIZE;
if (Util.isValidDimensions(overrideWidth, overrideHeight)) {
onSizeReady(overrideWidth, overrideHeight);
} else {
target.getSize(this);
}
// 使用一個佔位符先頂替
if ((status == Status.RUNNING || status == Status.WAITING_FOR_SIZE)
&& canNotifyStatusChanged()) {
target.onLoadStarted(getPlaceholderDrawable());
}
}
}
複製代碼
那接下來要講述的內容就應該是他的一些大小設置問題了,Glide
究竟是用什麼樣的方式完成大小的設置的呢?
onSizeReady(overrideWidth, overrideHeight)
public void onSizeReady(int width, int height) {
stateVerifier.throwIfRecycled();
synchronized (requestLock) {
// .....
status = Status.RUNNING;
// 對長寬從新進行預估
float sizeMultiplier = requestOptions.getSizeMultiplier();
this.width = maybeApplySizeMultiplier(width, sizeMultiplier);
this.height = maybeApplySizeMultiplier(height, sizeMultiplier);
loadStatus =
engine.load(各類參數);
// .....
}
}
複製代碼
經過觀察對onSizeReady()
函數發現,他使用的方案其實又是一個名叫作engine.load()
的方式。
public <R> LoadStatus load(各類參數) {
EngineResource<?> memoryResource;
synchronized (this) {
memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
if (memoryResource == null) {
return waitForExistingOrStartNewJob(各類參數);
}
}
cb.onResourceReady(memoryResource, DataSource.MEMORY_CACHE);
return null;
}
複製代碼
上述是我省略事後的代碼,他表達意思其實很是之簡單:
(1)內存裏有數據,你就從我內存裏拿。
(2)內存裏沒數據,那你就本身建立一個。
這樣想來,問題又要往下繼續延伸了,正常來講咱們沒有數據啊,那就要去調用這個waitForExistingOrStartNewJob()
方法,來完成圖片數據的獲取了。
private <R> LoadStatus waitForExistingOrStartNewJob(各類參數) {
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb, callbackExecutor);
return new LoadStatus(cb, current);
}
EngineJob<R> engineJob =
engineJobFactory.build(各類參數);
DecodeJob<R> decodeJob =
decodeJobFactory.build(各類參數);
jobs.put(key, engineJob); // 對當前驅動工做進行緩存操做
engineJob.addCallback(cb, callbackExecutor);
engineJob.start(decodeJob); // 開啓圖片獲取工做
return new LoadStatus(cb, engineJob);
}
複製代碼
可以注意到有出現兩個新的類EngineJob
和DecodeJob
,轉換成中文去理解就是工做驅動器和解碼工做,而且EngineJob
內部與線程池搭噶,最後確定用於完成最後的圖片獲取工做,而DecodeJob
做爲被運行的工做,處理邏輯就應該在其之中。
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. 數據緩存:DataCacheGenerator
// 3. 網絡資源: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);
}
}
複製代碼
其實上述內容中已經開始講述到咱們常見的三大緩存了,也就是網絡緩存、磁盤緩存和內存緩存,這段代碼中其實已經開始涉及網絡緩存和磁盤緩存了。
SourceGenerator:關於網絡緩存
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();
// 只對Source這個枚舉類型相應
if (stage == Stage.SOURCE) {
reschedule();
return;
}
}
// 已完成就通知失敗
if ((stage == Stage.FINISHED || isCancelled) && !isStarted) {
notifyFailed();
}
}
// 1-->
public boolean startNext() {
// 須要數據有緩存才行
if (dataToCache != null) {
Object data = dataToCache;
dataToCache = null;
cacheData(data);
}
if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
return true;
}
sourceCacheGenerator = null;
loadData = null;
boolean started = false;
while (!started && hasNextModelLoader()) {
// 從映射表找出可以對應上的圖片類型的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;
}
複製代碼
針對註釋1進行探討,這裏的話,咱們就儘可能不放代碼查看了,由於看了這麼多代碼,你確定也累了。其實你可以猜想到它的下一步是網絡請求,那若是獲取成功了,是要直接進行圖片數據的顯示嗎?那三次緩存應該在什麼時機進行操做呢?由於代碼量的緣由,這裏咱們用圖來展現流程。
從圖中能夠知道,其實從網絡獲取的資源最後仍是要被放到磁盤中進行緩存的,而磁盤緩存成功以後,接下來要乾的事情就是要去通知View
把獲取的數據進行解碼。這裏你是否有必定的疑問了?
你沒有聽錯,就是解碼,若是你去各個官方查看圖片的時候,不少給的都是後期從新被編碼過的數據,自己數據其實並不可以在直接運行的,而解碼就是讓圖片正式可視化的必經之路,也就是DecodeJob
的本質工做了,對應的函數就是decodeFromRetrievedData()
方法,把磁盤中拷貝出來的數據要進行解碼操做。
private void decodeFromRetrievedData() {
Resource<R> resource = null;
// 將網絡獲取的數據進行解碼操做
try {
resource = decodeFromData(currentFetcher, currentData, currentDataSource); // 1 -->
} catch (GlideException e) {
}
// 解碼完成,發出通知
if (resource != null) {
notifyEncodeAndRelease(resource, currentDataSource); // 2-->
} else {
runGenerators();
}
}
複製代碼
你可以發現我在這段代碼中打了兩個註釋,其實對應的就是兩大操做解碼完成,通知能夠顯示了。
decodeFromData(currentFetcher, currentData, currentDataSource);
下面會給出一段很長的深度調用代碼。
(1)resource = decodeFromData(currentFetcher, currentData, currentDataSource);
(2)Resource<R> result = decodeFromFetcher(data, dataSource);
(3)return path.load(
rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
(4)return loadWithExceptionList(rewinder, options, width, height, decodeCallback, throwables);
(5)result = path.decode(rewinder, width, height, options, decodeCallback);
(6)
public Resource<Transcode> decode( DataRewinder<DataType> rewinder, int width, int height, @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
// 這裏會有不少轉化的方法,通常來講對圖片最多見的就是轉成Bitmap
Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
return transcoder.transcode(transformed, options);
}
複製代碼
在decode()
這個函數其實作了三件事:
decodeResource
將原始數據轉換成咱們原始圖片的過程;callback.onResourceDecoded()
是當獲得了原始圖片以後對圖片繼續處理過程;transcoder.transcode()
會使用BitmapDrawableTranscoder
進行再包裝decodeResource中能夠轉化的部分解碼器
那這個時候你就正式拿到了一張圖片了,那下一步還須要幹嗎???顯示啊!!!廢了這麼大週摺,還不趕忙拿去顯示,不是作了一大堆無用功嘛?
notifyEncodeAndRelease(resource, currentDataSource);
只看少許代碼來完成這項工做
(1)notifyComplete(result, dataSource);
(2)
private void notifyComplete(Resource<R> resource, DataSource dataSource) {
setNotifiedOrThrow();
callback.onResourceReady(resource, dataSource);
}
複製代碼
你是否有注意到這樣的問題,onResourceReady()
是否是有點眼熟,在很上面的glideContext.buildImageViewTarget(view, transcodeClass)
,也就是構建放置的目標中咱們就已經講到過這個方法了,最後會經過一個set()
的方法來將數據進行放置。
那基本上來講,上面就是一個比較詳細的Glide
的源碼分析,由於代碼是在太多了,因此我這裏刪去了不少。
其實你會發現我並無正式講完三級緩存,還差一個內存緩存沒講不是?
其實這是一個很早就被用到的方法,他對應的位置就在SingleRequest
被調用了OnSizeReady()
方法的時候有個engine.load()
,裏面就包含了第三級緩存內存緩存,裏面對應的是這樣的一段代碼memoryResource = loadFromMemory(key, isMemoryCacheable, startTime);
以及他深度調用後的EngineResource<?> active = loadFromActiveResources(key);
從活躍的的資源數據中進行尋找。一樣是一個很是簡單的實現手法。
final Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
複製代碼
就是經過一個Map
對數據進行了保存,這樣從複用的角度上來看就被比較好的繼承了。
但若是不是活躍資源數據呢?
不要着急,還有一些數據還會在cache
的變量中被保存着,這個方法裏就是用了咱們常常會說起到的LRUCache
的一個淘汰算法,這裏的詳細請查看個人另一篇文章:Glide都在用的LruCache,你學會了嗎?。