和以前的文章會有必定的不一樣,這主要是由於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
這個類,那天然是有必要對這個類進行探究的。markdown
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
也就是主線程的,那說明最後異步通訊也就直接扔到主線程完成了。網絡
(2)經過get()
函數,能夠發現其實分爲兩個部分。一是再一層的get()
方法;二是supportFragmentGet()
或者是FragmentGet()
方法。app
他們最後的任務都是爲了建立出一個RequestManager
,可是咱們得關注一下它的建立方式。異步
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,你學會了嗎?。