摘要:如果你是第一次看我的的源碼分析系列文章,這里強(qiáng)烈推薦你先閱讀我的前面兩篇文章源碼分析之與源碼分析之。其中是用來(lái)管理推遲資源釋放的。發(fā)送預(yù)處理請(qǐng)求,獲取相應(yīng)類型的緩存數(shù)據(jù)。當(dāng)數(shù)據(jù)源已經(jīng)獲取到時(shí),發(fā)送通知給訂閱者,因此分別回調(diào)訂閱者的方法。
如果你是第一次看我的Fresco的源碼分析系列文章,這里強(qiáng)烈推薦你先閱讀我的前面兩篇文章Fresco源碼分析之DraweeView與Fresco源碼分析之Hierarchy。好了,下面進(jìn)入正題。在上篇文章中我們提到,在Fresco中關(guān)于圖片的緩存、請(qǐng)求與顯示邏輯處理都在Controller中。那么Controller到底是如何貫穿這些功能的呢?我們先從它的出生開始。
SuppilerPipelineDraweeControllerBuilderSupplier是一個(gè)供應(yīng)商,主要實(shí)現(xiàn)了Supplier
@Override public PipelineDraweeControllerBuilder get() { return new PipelineDraweeControllerBuilder( mContext, mPipelineDraweeControllerFactory, mImagePipeline, mBoundControllerListeners); }
在生成的builder中有4個(gè)參數(shù),第一個(gè)是Context再熟悉不過(guò)了;第二個(gè)是Controller的工廠;第三個(gè)是數(shù)據(jù)管道ImagePipeline;第四個(gè)是listener的set集合,主要用在圖片請(qǐng)求之后的監(jiān)聽回調(diào)。下面詳細(xì)說(shuō)明后面三個(gè)參數(shù)內(nèi)容與作用。
PipelineDraweeControllerFactory在這個(gè)類中主要就兩個(gè)方法,分別為internalCreateController與newController,對(duì)外的方法就一個(gè)newController。這個(gè)兩個(gè)方法都是用來(lái)創(chuàng)建PipelineDraweeController對(duì)象。其中newController內(nèi)部就是調(diào)用了internalCreateController來(lái)進(jìn)行創(chuàng)建PipelineDraweeController實(shí)例。
protected PipelineDraweeController internalCreateController( Resources resources, DeferredReleaser deferredReleaser, DrawableFactory animatedDrawableFactory, Executor uiThreadExecutor, MemoryCachememoryCache, @Nullable ImmutableList globalDrawableFactories, @Nullable ImmutableList customDrawableFactories, Supplier >> dataSourceSupplier, String id, CacheKey cacheKey, Object callerContext) { PipelineDraweeController controller = new PipelineDraweeController( resources, deferredReleaser, animatedDrawableFactory, uiThreadExecutor, memoryCache, dataSourceSupplier, id, cacheKey, callerContext, globalDrawableFactories); controller.setCustomDrawableFactories(customDrawableFactories); return controller; }
其中DeferredReleaser是用來(lái)管理推遲資源釋放的。我們?cè)谥暗奈恼乱呀?jīng)提到,在onAttach中會(huì)進(jìn)行加載資源,而onDetach中又會(huì)釋放資源。因?yàn)樵?strong>Fresco中往往會(huì)在onDetach與onAttach之間頻繁切換(view的顯隱、繪制與Controller的設(shè)置都會(huì)調(diào)用),并且它們都處于在同一個(gè)looper(其實(shí)就是主進(jìn)程的looper)中。如果在onDetach時(shí)馬上釋放資源的話,這樣會(huì)造成資源的濫用,導(dǎo)致不必要的資源加載與釋放回收。所以就用了這個(gè)資源推遲釋放的機(jī)制(內(nèi)部原理是使用了set集合的唯一性的特性)。
dataSourceSupplier是DataSource的供應(yīng)商,用來(lái)提供DataSource實(shí)例。而DataSource是用來(lái)獲取與存儲(chǔ)請(qǐng)求結(jié)果的,相當(dāng)與圖片數(shù)據(jù)源。這些都會(huì)在后續(xù)的Controller中使用到。
ImagePipeline既然它是數(shù)據(jù)管道,自然是與網(wǎng)絡(luò)請(qǐng)求與緩存數(shù)據(jù)有關(guān)。其實(shí)我們可以把它理解為多個(gè)管道的集合,最終顯示的圖片資源就是來(lái)自于它們中的其中一個(gè)。下面介紹其中的主要方法:
fetchDecodedImage() 發(fā)送請(qǐng)求,返回decode image的數(shù)據(jù)源。
fetchEncodedImage() 發(fā)送請(qǐng)求,返回encoded image的數(shù)據(jù)源。
prefetchToBitmapCache() 發(fā)送預(yù)處理請(qǐng)求,獲取預(yù)處理的bitmap緩存數(shù)據(jù)。
prefetchToDiskCache() 發(fā)送預(yù)處理請(qǐng)求,獲取預(yù)處理的磁盤緩存數(shù)據(jù)。
submitFetchRequest() 發(fā)送請(qǐng)求,獲取相應(yīng)類型的數(shù)據(jù)源。
submitPrefetchRequest() 發(fā)送預(yù)處理請(qǐng)求,獲取相應(yīng)類型的緩存數(shù)據(jù)。
這里用的最多的還是fetchDecodedImage()
public DataSource> fetchDecodedImage( ImageRequest imageRequest, Object callerContext, ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit) { try { Producer > producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest); return submitFetchRequest( producerSequence, imageRequest, lowestPermittedRequestLevelOnSubmit, callerContext); } catch (Exception exception) { return DataSources.immediateFailedDataSource(exception); } }
這里主要涉及到Producer,這是一個(gè)生產(chǎn)者,內(nèi)部只有一個(gè)公共接口方法void produceResults(Consumer
關(guān)于Producer后續(xù)有時(shí)間的話會(huì)多帶帶開篇文章詳細(xì)分析。ControllerListener
如果你對(duì)ControllerListener不熟悉的話,那么BaseControllerListener應(yīng)該或多或少使用過(guò)吧。它其實(shí)就是ControllerListener的空實(shí)現(xiàn)。既然是監(jiān)聽回調(diào),那么來(lái)看下它提供的回調(diào)方法與調(diào)用時(shí)機(jī)。
void onSubmit(String id, Object callerContext) 在發(fā)送請(qǐng)求的時(shí)候回調(diào)
void onFinalImageSet(String id, @Nullable INFO imageInfo, @Nullable Animatable animatable) 在最終設(shè)置image圖片時(shí)回調(diào),其中imageInfo包含圖片的相關(guān)基本信息(width、height與quality)
void onIntermediateImageSet(String id, @Nullable INFO imageInfo) 在發(fā)送請(qǐng)求與最終圖片設(shè)置的過(guò)程中回調(diào)
void onIntermediateImageFailed(String id, Throwable throwable) 在發(fā)送請(qǐng)求與最終失敗的過(guò)程中回調(diào)
void onFailure(String id, Throwable throwable) 發(fā)送請(qǐng)求失敗時(shí)回調(diào)
void onRelease(String id) 資源釋放時(shí)回調(diào)
ControllerBuilder既然是builder模式,最終的目的自然就是用來(lái)創(chuàng)建Controller,所以我們可以直接奔著它的目的來(lái)分析。在這里Controller的builder類是PipelineDraweeControllerBuilder。我們找到它的build()發(fā)現(xiàn)在它的父類AbstractDraweeControllerBuilder中。但最終的創(chuàng)建實(shí)例方法還是調(diào)用了obtainController()抽象方法。所以經(jīng)過(guò)反轉(zhuǎn)還是回到了PipelineDraweeControllerBuilder,那么我們直接來(lái)看下它創(chuàng)建方式。
@Override protected PipelineDraweeController obtainController() { DraweeController oldController = getOldController(); PipelineDraweeController controller; if (oldController instanceof PipelineDraweeController) { controller = (PipelineDraweeController) oldController; controller.initialize( obtainDataSourceSupplier(), generateUniqueControllerId(), getCacheKey(), getCallerContext(), mCustomDrawableFactories); } else { controller = mPipelineDraweeControllerFactory.newController( obtainDataSourceSupplier(), generateUniqueControllerId(), getCacheKey(), getCallerContext(), mCustomDrawableFactories); } return controller; }
通過(guò)上面的代碼,邏輯已經(jīng)很明顯了。首先判斷是否已經(jīng)存在Controller,如果存在的話就無(wú)需創(chuàng)建新的實(shí)例,只需調(diào)用initialize()方法進(jìn)行重寫初始化;如果不存在,那么就調(diào)用我們文章之前分析的PipelineDraweeControllerFactory中的newController()來(lái)創(chuàng)建新的實(shí)例。這里主要的參數(shù)還是obtainDataSourceSupplier(),之前也簡(jiǎn)單提到了,它是DataSource的供應(yīng)者。那么我們來(lái)看下Supplier的創(chuàng)建
protected Supplier> getDataSourceSupplierForRequest( final REQUEST imageRequest, final CacheLevel cacheLevel) { final Object callerContext = getCallerContext(); return new Supplier >() { @Override public DataSource get() { return getDataSourceForRequest(imageRequest, callerContext, cacheLevel); } @Override public String toString() { return Objects.toStringHelper(this) .add("request", imageRequest.toString()) .toString(); } }; }
在這個(gè)方法中,我們一眼就看到了Supplier的創(chuàng)建,之前也提到它只有一個(gè)get()方法,就是用來(lái)提供所以需要的DataSource。在這里也是如此,這里它調(diào)用了getDataSourceForRequest()方法,該方法是一個(gè)抽象方法,細(xì)節(jié)實(shí)現(xiàn)由它的子類實(shí)現(xiàn),所以我們可以再次回到getDataSourceForRequest,在其中就能夠搜索到getDataSourceForRequest()方法
@Override protected DataSource> getDataSourceForRequest( ImageRequest imageRequest, Object callerContext, CacheLevel cacheLevel) { return mImagePipeline.fetchDecodedImage( imageRequest, callerContext, convertCacheLevelToRequestLevel(cacheLevel)); }
看到上面的方法實(shí)現(xiàn)方法是否眼熟呢?這也是我們上面所提到的ImagePipleline中的方法,這里就不在多做分析了。這樣Controller就與獲取數(shù)據(jù)的通道建立了聯(lián)系。那么下面我們就轉(zhuǎn)戰(zhàn)到Controller中,看看它到底做了什么。
ControllerPipelineDraweeController繼承于AbstractDraweeController,在PipelineDraweeController中主要的方法有三個(gè)
Drawable createDrawable(CloseableImage closeableImage) 這是內(nèi)部類DrawableFactory中的方法,是一個(gè)工廠,不言而喻它是用來(lái)創(chuàng)建Drawable的,在數(shù)據(jù)源返回的時(shí)候回調(diào),進(jìn)而顯示到Hierarchy層。
getDataSource() 獲取數(shù)據(jù)源通道,與其建立聯(lián)系。
void setHierarchy(@Nullable DraweeHierarchy hierarchy) 設(shè)置Hierarchy圖層,內(nèi)部持有的其實(shí)是SettableDraweeHierarchy接口對(duì)象。所以內(nèi)部調(diào)用的也就是它的6個(gè)接口方法。之前的文章也有提及,用來(lái)控制圖片加載過(guò)程中的顯示邏輯。
其余的邏輯處理都在它的父類AbstractDraweeController中。在之前我們多次提及到onAttach與onDetach方法,它們分別是處理數(shù)據(jù)加載與釋放。
onAttach@Override public void onAttach() { if (FLog.isLoggable(FLog.VERBOSE)) { FLog.v( TAG, "controller %x %s: onAttach: %s", System.identityHashCode(this), mId, mIsRequestSubmitted ? "request already submitted" : "request needs submit"); } //事件記錄器 mEventTracker.recordEvent(Event.ON_ATTACH_CONTROLLER); Preconditions.checkNotNull(mSettableDraweeHierarchy); //取消資源推遲釋放機(jī)制,防止資源被釋放 mDeferredReleaser.cancelDeferredRelease(this); mIsAttached = true; if (!mIsRequestSubmitted) { submitRequest(); } }
在這個(gè)方法中mEventTracker是事件記錄器,默認(rèn)是開啟的,如果要關(guān)閉則需要在Fresco.initialize()之前調(diào)用DraweeEventTracker.disable()關(guān)閉;然后就是將其從資源推遲釋放機(jī)制中取消;最后就是調(diào)用submitRequest()發(fā)送數(shù)據(jù)源請(qǐng)求。
protected void submitRequest() { final T closeableImage = getCachedImage(); //1.判斷內(nèi)存緩存中是否存在 if (closeableImage != null) { mDataSource = null; mIsRequestSubmitted = true; mHasFetchFailed = false; mEventTracker.recordEvent(Event.ON_SUBMIT_CACHE_HIT); //1.1數(shù)據(jù)獲取中通知回調(diào) getControllerListener().onSubmit(mId, mCallerContext); //1.2數(shù)據(jù)處理 onNewResultInternal(mId, mDataSource, closeableImage, 1.0f, true, true); return; } mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT); //2.通過(guò)DataSource獲取數(shù)據(jù)源 //2.1數(shù)據(jù)獲取中通知回調(diào) getControllerListener().onSubmit(mId, mCallerContext); mSettableDraweeHierarchy.setProgress(0, true); mIsRequestSubmitted = true; mHasFetchFailed = false; mDataSource = getDataSource(); if (FLog.isLoggable(FLog.VERBOSE)) { FLog.v( TAG, "controller %x %s: submitRequest: dataSource: %x", System.identityHashCode(this), mId, System.identityHashCode(mDataSource)); } final String id = mId; final boolean wasImmediate = mDataSource.hasResult(); //內(nèi)部請(qǐng)求數(shù)據(jù)回調(diào),當(dāng)數(shù)據(jù)源返回時(shí)回調(diào) final DataSubscriberdataSubscriber = new BaseDataSubscriber () { @Override public void onNewResultImpl(DataSource dataSource) { // isFinished must be obtained before image, otherwise we might set intermediate result // as final image. boolean isFinished = dataSource.isFinished(); float progress = dataSource.getProgress(); T image = dataSource.getResult(); //2.2數(shù)據(jù)處理 if (image != null) { //成功處理 onNewResultInternal(id, dataSource, image, progress, isFinished, wasImmediate); } else if (isFinished) { //失敗處理 onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true); } } @Override public void onFailureImpl(DataSource dataSource) { //失敗處理 onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true); } @Override public void onProgressUpdate(DataSource dataSource) { boolean isFinished = dataSource.isFinished(); float progress = dataSource.getProgress(); //數(shù)據(jù)進(jìn)度處理 onProgressUpdateInternal(id, dataSource, progress, isFinished); } }; //數(shù)據(jù)源訂閱回調(diào)注冊(cè) mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor); }
邏輯方面的處理,上面代碼中已經(jīng)詳細(xì)注釋了,總的來(lái)說(shuō)就是先從內(nèi)存中獲取如果存在就直接拿來(lái)用,否則就通過(guò)DataSource從網(wǎng)絡(luò)或者是本地資源中獲取。使用DataSource方式會(huì)使用到DataSubscriber,即訂閱方式。當(dāng)數(shù)據(jù)源已經(jīng)獲取到時(shí),發(fā)送通知給訂閱者,因此分別回調(diào)訂閱者的方法。上述兩種方式只要成功了都會(huì)交由onNewResultInternal()處理,而失敗則由onFailureInternal()處理,同時(shí)請(qǐng)求進(jìn)度處理由onProgressUpdateInternal()處理。
private void onNewResultInternal( String id, DataSourcedataSource, @Nullable T image, float progress, boolean isFinished, boolean wasImmediate) { // ignore late callbacks (data source that returned the new result is not the one we expected) if (!isExpectedDataSource(id, dataSource)) { logMessageAndImage("ignore_old_datasource @ onNewResult", image); releaseImage(image); dataSource.close(); return; } mEventTracker.recordEvent( isFinished ? Event.ON_DATASOURCE_RESULT : Event.ON_DATASOURCE_RESULT_INT); // create drawable Drawable drawable; try { drawable = createDrawable(image); } catch (Exception exception) { logMessageAndImage("drawable_failed @ onNewResult", image); releaseImage(image); onFailureInternal(id, dataSource, exception, isFinished); return; } T previousImage = mFetchedImage; Drawable previousDrawable = mDrawable; mFetchedImage = image; mDrawable = drawable; try { // set the new image if (isFinished) { logMessageAndImage("set_final_result @ onNewResult", image); mDataSource = null; //通過(guò)hierarchy(GenericDraweeHierarchy)來(lái)設(shè)置image mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate); getControllerListener().onFinalImageSet(id, getImageInfo(image), getAnimatable()); // IMPORTANT: do not execute any instance-specific code after this point } else { logMessageAndImage("set_intermediate_result @ onNewResult", image); mSettableDraweeHierarchy.setImage(drawable, progress, wasImmediate); getControllerListener().onIntermediateImageSet(id, getImageInfo(image)); // IMPORTANT: do not execute any instance-specific code after this point } } finally { if (previousDrawable != null && previousDrawable != drawable) { releaseDrawable(previousDrawable); } if (previousImage != null && previousImage != image) { logMessageAndImage("release_previous_result @ onNewResult", previousImage); releaseImage(previousImage); } } }
這里我們主要就看里面的兩個(gè)try。
第一個(gè)使用createDrawable(image)將拿到的數(shù)據(jù)源轉(zhuǎn)變成Drawable,這個(gè)方法的具體實(shí)現(xiàn)是在子類中實(shí)現(xiàn)(上面也有提及)。
第二個(gè)分為兩種情況,一方面如果數(shù)據(jù)源已經(jīng)全部獲取完,則直接調(diào)用SettableDraweeHierarchy接口的setImage()方法將圖片設(shè)置到Hierarchy圖層上,同時(shí)調(diào)用Listener的回調(diào)方法onFinalImageSet();另一方面如果數(shù)據(jù)源還在獲取中,也是調(diào)用SettableDraweeHierarchy接口的setImage()方法,只是其中的參數(shù)progress根據(jù)進(jìn)度來(lái)設(shè)置而已,由于還處于資源獲取中所以調(diào)用onIntermediateImageSet()回調(diào)。
這樣Controller就與Hierarchy聯(lián)系起來(lái)了,將需要的圖片設(shè)置到顯示的圖片中。
對(duì)于SettableDraweeHierarchy中的這些方法如果不理解的可以回過(guò)頭去看我之前的這篇文章Fresco源碼分析之Hierarchy
由于源碼太多,對(duì)于onFailureInternal()與onProgressUpdateInternal()這里就不貼出源碼來(lái)進(jìn)行分析了。原理與調(diào)用的方法基本類似,如果想看源碼的可以點(diǎn)這里
onDetach@Override public void onDetach() { if (FLog.isLoggable(FLog.VERBOSE)) { FLog.v(TAG, "controller %x %s: onDetach", System.identityHashCode(this), mId); } mEventTracker.recordEvent(Event.ON_DETACH_CONTROLLER); mIsAttached = false; mDeferredReleaser.scheduleDeferredRelease(this); }
相對(duì)于之前的分析onDetach()就簡(jiǎn)單多了,這里它只是對(duì)資源進(jìn)行釋放,釋放的策略也是推遲釋放策略DeferredReleaser。
End本篇文章主要分析了Fresco中的Controller相關(guān)處理邏輯,它控制著Hierarchy顯示邏輯,同時(shí)它是數(shù)據(jù)源的獲取橋梁通過(guò)DataSource來(lái)鏈接數(shù)據(jù)源的獲取。那么問(wèn)題又來(lái)了,DataSource又是如何產(chǎn)生的呢?同時(shí)它的內(nèi)部邏輯又是如何的呢?這就涉及到Producer了,敬請(qǐng)關(guān)注下篇文章Fresco源碼分析之Producer
Fresco源碼分析系列Github地址
關(guān)注 RecommendFresco源碼分析之DraweeView
Fresco源碼分析之Hierarchy
Android共享動(dòng)畫兼容實(shí)現(xiàn)
Kotlin最佳實(shí)踐
RecyclerView下拉刷新與上拉更多
Android高仿微信之mvp實(shí)現(xiàn)(四)
tensorflow-梯度下降,有這一篇就足夠了
博客
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68076.html
摘要:首先這是對(duì)的源碼分析,所以在看這篇文章之前你應(yīng)該要有使用的基礎(chǔ),如果沒(méi)有的強(qiáng)烈推薦看下官方文檔。在中統(tǒng)一由來(lái)替代。關(guān)于后續(xù)文章會(huì)詳細(xì)分析。在其內(nèi)部的,是用來(lái)記錄事件的傳遞,方便的調(diào)試。這次主要是分析了中的基本組件與它的子類。 在Android中圖片加載的框架很多,例如:Fresco、Picasso、Glide與Imageloader。它們都有各自的優(yōu)點(diǎn),但總的來(lái)說(shuō),使用起來(lái)方便簡(jiǎn)單、可...
摘要:最終的顯隱操作都會(huì)轉(zhuǎn)化為在方法中進(jìn)行操作。主要是通過(guò)與數(shù)組來(lái)控制數(shù)組中各個(gè)的值,即顯隱它繼承于,顧名思義通過(guò)矩陣來(lái)改變狀態(tài)。 上篇文章我們分析了Fresco中的DraweeView,對(duì)其中的一些原理以及方法進(jìn)行了解析。在這過(guò)程中我們了解到,DraweeView中是通過(guò)DraweeHolder來(lái)統(tǒng)一管理的。而DraweeHolder又是用來(lái)統(tǒng)一管理相關(guān)的Hierarchy與Control...
閱讀 2997·2021-09-10 10:50
閱讀 3196·2019-08-30 14:19
閱讀 3526·2019-08-29 17:31
閱讀 3257·2019-08-29 16:43
閱讀 2201·2019-08-29 14:05
閱讀 2098·2019-08-29 13:17
閱讀 2054·2019-08-26 13:25
閱讀 1770·2019-08-26 12:20