Fresco有三级缓存,分别为Bitmap缓存、未解码图片的内存缓存与磁盘缓存。如果这三级缓存没有找到对应请求的图片时,才会走网络请求这条路。那么Fresco又是怎么管理这些缓存,或者说如何从这些步骤中获取到最终的Result并且返回给UI层的呢?这个时候就该Producer出场了。
Producer
首先Producer是一个接口,它内部就一个待实现的方法produceResults
1 2 3 4 5 6 7 8 9 10
| public interface Producer<T> { /** * Start producing results for given context. Provided consumer is notified whenever progress is * made (new value is ready or error occurs). * @param consumer * @param context */ void produceResults(Consumer<T> consumer, ProducerContext context); }
|
Producer主要用来执行对图片资源获取的多样方式处理。例如:网络方式、磁盘缓存方式、内存缓存方式、解码方式与一些旋转变换等操作。这里的Consumer主要作为回调,由于Producer多样方式的处理逻辑是通过内部递归的方式进行的,所以递归回调处理是必不可少的;同时对于内部递归时一些数据的传递,则是通过ProducerContext来进行。ProducerContext只是一个接口,提供获取需要传递的数据的抽象方法。
Result处理
我们先来看下最终的Producer返回的Result的处理方式。看下它是如果将数据传递给UI层,使得UI更新加载的图片视图。
在上一篇关于Controller的文章中,提到对于DataSource是通过ImagePipeline中的fetchDecodeImage方法获取的。我们来重温它的方法实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public DataSource<CloseableReference<CloseableImage>> fetchDecodedImage( ImageRequest imageRequest, Object callerContext, ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit) { try { Producer<CloseableReference<CloseableImage>> producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest); return submitFetchRequest( producerSequence, imageRequest, lowestPermittedRequestLevelOnSubmit, callerContext); } catch (Exception exception) { return DataSources.immediateFailedDataSource(exception); } }
|
在这里我们如愿看到了Producer,它的内部递归先不看,我们先看下一步submitFetchRequest。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| private <T> DataSource<CloseableReference<T>> submitFetchRequest( Producer<CloseableReference<T>> producerSequence, ImageRequest imageRequest, ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit, Object callerContext) { final RequestListener requestListener = getRequestListenerForRequest(imageRequest); try { ImageRequest.RequestLevel lowestPermittedRequestLevel = ImageRequest.RequestLevel.getMax( imageRequest.getLowestPermittedRequestLevel(), lowestPermittedRequestLevelOnSubmit); SettableProducerContext settableProducerContext = new SettableProducerContext( imageRequest, generateUniqueFutureId(), requestListener, callerContext, lowestPermittedRequestLevel, /* isPrefetch */ false, imageRequest.getProgressiveRenderingEnabled() || imageRequest.getMediaVariations() != null || !UriUtil.isNetworkUri(imageRequest.getSourceUri()), imageRequest.getPriority()); return CloseableProducerToDataSourceAdapter.create( producerSequence, settableProducerContext, requestListener); } catch (Exception exception) { return DataSources.immediateFailedDataSource(exception); } }
|
在这里让我们定位到SettableProducerContext,它实现了ProducerContext接口,用来对producerSequence的内部递归的数据传递。例如:ImageRequest、Id、ProducerListener与RequestLevel等。
那么下一步就是真正的DataSource的创建CloseableProducerToDataSourceAdapter.creat()。它继承于AbstractProducerToDataSourceAdapter,它的父类AbstractDataSource实现了DataSource接口。在AbstractProducerToDataSourceAdapter的构造方法中能够找到我们想要的东西。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| protected AbstractProducerToDataSourceAdapter( Producer<T> producer, SettableProducerContext settableProducerContext, RequestListener requestListener) { mSettableProducerContext = settableProducerContext; mRequestListener = requestListener; mRequestListener.onRequestStart( settableProducerContext.getImageRequest(), mSettableProducerContext.getCallerContext(), mSettableProducerContext.getId(), mSettableProducerContext.isPrefetch()); //PostprocessedBitmapMemoryCacheProducer producer.produceResults(createConsumer(), settableProducerContext); }
|
settableProducerContext数据传递使用的出神入化。调用了Producer的produceResults方法,开启递归调用各个Producer,因为每一个Producer的produceResults方法中如果没有获取到最终的图片资源,都会调用下一个Producer的produceResults方法,最终通过Consumer回调到最初的Producer中,即createConsumer()方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| private Consumer<T> createConsumer() { return new BaseConsumer<T>() { @Override protected void onNewResultImpl(@Nullable T newResult, @Status int status) { AbstractProducerToDataSourceAdapter.this.onNewResultImpl(newResult, status); } @Override protected void onFailureImpl(Throwable throwable) { AbstractProducerToDataSourceAdapter.this.onFailureImpl(throwable); } @Override protected void onCancellationImpl() { AbstractProducerToDataSourceAdapter.this.onCancellationImpl(); } @Override protected void onProgressUpdateImpl(float progress) { AbstractProducerToDataSourceAdapter.this.setProgress(progress); } }; }
|
在createConsumer()中分别调用了onNewResultImpl、onFailureImpl、setProgress与onCancellationImpl方法。分别代表成功的回调、失败的回调、请求进度回调与请求取消回调。对于前三回调都会触发AbstractDataSource中的notifyDataSubscribers()方法。例如onNewResultImpl方法
1 2 3 4 5 6 7 8 9 10 11 12
| protected void onNewResultImpl(@Nullable T result, int status) { boolean isLast = BaseConsumer.isLast(status); //setResult将结果传入AbstractDataSource中 if (super.setResult(result, isLast)) { if (isLast) { mRequestListener.onRequestSuccess( mSettableProducerContext.getImageRequest(), mSettableProducerContext.getId(), mSettableProducerContext.isPrefetch()); } } }
|
调用了父类的super.setResult()方法。
1 2 3 4 5 6 7 8
| protected boolean setResult(@Nullable T value, boolean isLast) { //将从Producer中获取都的数据源保存到mResult中,外部可以通过getResult获取。 boolean result = setResultInternal(value, isLast); if (result) { notifyDataSubscribers(); } return result; }
|
Result保存到DataSource中的mResult中,在之前的Controller中,就可以通过调用DataSource的getResult方法获取请求的Result。Controller对DataSource的订阅也将通过notifyDataSubscribers()方法进行通知。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| private void notifyDataSubscribers() { final boolean isFailure = hasFailed(); final boolean isCancellation = wasCancelled(); //通知所有的订阅者 for (Pair<DataSubscriber<T>, Executor> pair : mSubscribers) { notifyDataSubscriber(pair.first, pair.second, isFailure, isCancellation); } } private void notifyDataSubscriber( final DataSubscriber<T> dataSubscriber, final Executor executor, final boolean isFailure, final boolean isCancellation) { executor.execute( new Runnable() { @Override public void run() { if (isFailure) { dataSubscriber.onFailure(AbstractDataSource.this); } else if (isCancellation) { dataSubscriber.onCancellation(AbstractDataSource.this); } else { dataSubscriber.onNewResult(AbstractDataSource.this); } } }); }
|
executor.execute()方法解释了一切。调用了Controller中传递过来的dataSubscriber的各个回调。那么Result的处理过程就走通了。
如需了解Controller,推荐阅读Fresco源码分析之Controller
Producer的兄弟姐妹
接下来我们来认识下Producer的家庭成员。回到最初的fetchDecodedImage()方法,我们找到如下代码。
1 2
| Producer<CloseableReference<CloseableImage>> producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
|
Producer的家庭成员的出生地都是ProducerSequenceFactory工厂。最先出生的是解码了的ImageProducer成员。通过getDecodeImageProducerSquence()方法获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public Producer<CloseableReference<CloseableImage>> getDecodedImageProducerSequence( ImageRequest imageRequest) { //通过Uri类型来获取不同的请求队列 Producer<CloseableReference<CloseableImage>> pipelineSequence = getBasicDecodedImageSequence(imageRequest); // 通过ImageRequestBuilder.setPostprocessor()设置, 一般为null。 // 作用是用来对获取到的Bitmap进行加工处理。例如:添加水印等。 if (imageRequest.getPostprocessor() != null) { pipelineSequence = getPostprocessorSequence(pipelineSequence); } //一般用来实验,ImagePipelineConfig.Builder->ImagePipelineExperiments->setBitmapPrepareToDraw //所以正常情况都为false if (mUseBitmapPrepareToDraw) { pipelineSequence = getBitmapPrepareSequence(pipelineSequence); } return pipelineSequence; }
|
上面代码的注释已经很清楚了,正常的流程只需关注getBasicDecodedImageSequence()方法。其它的都是对获取到的Result进行加工处理,并不是真正的Result获取步骤。那么继续看getBasicDecodedImageSequence。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| private Producer<CloseableReference<CloseableImage>> getBasicDecodedImageSequence( ImageRequest imageRequest) { Preconditions.checkNotNull(imageRequest); Uri uri = imageRequest.getSourceUri(); Preconditions.checkNotNull(uri, "Uri is null."); switch (imageRequest.getSourceUriType()) { case SOURCE_TYPE_NETWORK: return getNetworkFetchSequence(); case SOURCE_TYPE_LOCAL_VIDEO_FILE: return getLocalVideoFileFetchSequence(); case SOURCE_TYPE_LOCAL_IMAGE_FILE: return getLocalImageFileFetchSequence(); case SOURCE_TYPE_LOCAL_CONTENT: if (MediaUtils.isVideo(mContentResolver.getType(uri))) { return getLocalVideoFileFetchSequence(); } return getLocalContentUriFetchSequence(); case SOURCE_TYPE_LOCAL_ASSET: return getLocalAssetFetchSequence(); case SOURCE_TYPE_LOCAL_RESOURCE: return getLocalResourceFetchSequence(); case SOURCE_TYPE_QUALIFIED_RESOURCE: return getQualifiedResourceFetchSequence(); case SOURCE_TYPE_DATA: return getDataFetchSequence(); default: throw new IllegalArgumentException( "Unsupported uri scheme! Uri is: " + getShortenedUriString(uri)); } }
|
到这里就是一个分水岭,根据ImageRequest的SourceUriType,来决定不同类型资源的获取方式。这里以SOURCE_TYPE_NETWORK进行详细分析,getNetworkFetchSequence是网络请求的获取方法。
1 2 3 4 5 6 7
| private synchronized Producer<CloseableReference<CloseableImage>> getNetworkFetchSequence() { if (mNetworkFetchSequence == null) { mNetworkFetchSequence = newBitmapCacheGetToDecodeSequence(getCommonNetworkFetchToEncodedMemorySequence()); } return mNetworkFetchSequence; }
|
文章开头已经提及到Fresco有三级缓存:Bitmap缓存、未解码图片的内存缓存与磁盘缓存。根据上面的代码首先的从Bitmap缓存到图片解码,Bitmap缓存在newBitmapCacheGetToDecodeSequence中。至于图片解码直接调用了DecodeProducer进行实现。
Bitmap缓存系列Producer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToDecodeSequence( Producer<EncodedImage> inputProducer) { //解码Producer,对于图片的解码操作都在DecodeProducer中进行 DecodeProducer decodeProducer = mProducerFactory.newDecodeProducer(inputProducer); //获取Bitmap缓存资源 return newBitmapCacheGetToBitmapCacheSequence(decodeProducer); } private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToBitmapCacheSequence( Producer<CloseableReference<CloseableImage>> inputProducer) { BitmapMemoryCacheProducer bitmapMemoryCacheProducer = mProducerFactory.newBitmapMemoryCacheProducer(inputProducer); BitmapMemoryCacheKeyMultiplexProducer bitmapKeyMultiplexProducer = mProducerFactory.newBitmapMemoryCacheKeyMultiplexProducer(bitmapMemoryCacheProducer); ThreadHandoffProducer<CloseableReference<CloseableImage>> threadHandoffProducer = mProducerFactory.newBackgroundThreadHandoffProducer( bitmapKeyMultiplexProducer, mThreadHandoffProducerQueue); return mProducerFactory.newBitmapMemoryCacheGetProducer(threadHandoffProducer); }
|
在获取Bitmap缓存的过程中依次使用了BitmapMemoryCacheGetProducer、ThreadHandoffProducer、BitmapMemoryCacheKeyMultiplexProducer与BitmapMemoryCacheProducer。
如果想了解如果获取Bitmap缓存可以直接查看BitmapMemoryCacheProducer。由于篇幅受限,这里不对各个Producer内部实现细节进行解析,后续会单独开篇幅进行分析内部实现。
未解码图片的内存缓存与磁盘缓存系列Producer
回到之前的getNetworkFetchSequence方法,如果Bitmap缓存没有获取到最终的结果,那么会进入getCommonNetworkFetchToEncodedMemorySequence,进一步通过未解码的图片内存缓存与网络请求获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private synchronized Producer<EncodedImage> getCommonNetworkFetchToEncodedMemorySequence() { if (mCommonNetworkFetchToEncodedMemorySequence == null) { //未解码的图片缓存与磁盘缓存->网络请求 Producer<EncodedImage> inputProducer = newEncodedCacheMultiplexToTranscodeSequence( mProducerFactory.newNetworkFetchProducer(mNetworkFetcher)); //对图片的Meta Data进行转换 mCommonNetworkFetchToEncodedMemorySequence = ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer); //对JPEG格式的图片进行缩放与旋转操作 mCommonNetworkFetchToEncodedMemorySequence = mProducerFactory.newResizeAndRotateProducer( mCommonNetworkFetchToEncodedMemorySequence, mResizeAndRotateEnabledForNetwork, mUseDownsamplingRatio); } return mCommonNetworkFetchToEncodedMemorySequence; }
|
在这里首先会进行一些转换操作,例如:ResizeAndRotateProducer作用是对JPEG格式的图片根据EXIF的orientation与指定的rotation进行缩放与旋转操作。之后就是AddImageTransformMetaDataProducer对图片的Meta Data进行转换。最后调用newEncodedCacheMultiplexToTranscodeSequence进行未解码的图片缓存与磁盘缓存操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| private Producer<EncodedImage> newEncodedCacheMultiplexToTranscodeSequence( Producer<EncodedImage> inputProducer) { //对webp图片进行转码 if (WebpSupportStatus.sIsWebpSupportRequired && (!mWebpSupportEnabled || WebpSupportStatus.sWebpBitmapFactory == null)) { inputProducer = mProducerFactory.newWebpTranscodeProducer(inputProducer); } //磁盘缓存 inputProducer = newDiskCacheSequence(inputProducer); //未解码的图片缓存 EncodedMemoryCacheProducer encodedMemoryCacheProducer = mProducerFactory.newEncodedMemoryCacheProducer(inputProducer); //进行多路复用操作,通过未解码的缓存作为key,来获取对应的request return mProducerFactory.newEncodedCacheKeyMultiplexProducer(encodedMemoryCacheProducer); }
|
所以它的调用链是:EncodedCacheKeyMultiplexProducer -> EncodedMemoryCacheProducer -> newDiskCacheSequence -> WebpTranscodeProducer。
如果以上步骤都没有获取到最终的结果,那么将正式进入网络获取。入口在mProducerFactory.newNetworkFetchProducer(mNetworkFetcher))方法中,对应的Producer为NetworkFetchProducer。
网络请求Producer
网络请求是最终的获取方式,下面对NetworkFetchProducer进行简要分析,直接看它的最终方法produceResults。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Override public void produceResults(Consumer<EncodedImage> consumer, ProducerContext context) { context.getListener() .onProducerStart(context.getId(), PRODUCER_NAME); //保存fetch的请求状态信息(Consumer,ProducerContext) final FetchState fetchState = mNetworkFetcher.createFetchState(consumer, context); mNetworkFetcher.fetch( fetchState, new NetworkFetcher.Callback() { @Override public void onResponse(InputStream response, int responseLength) throws IOException { //该response即为最终请求图片的uri响应资源 NetworkFetchProducer.this.onResponse(fetchState, response, responseLength); } @Override public void onFailure(Throwable throwable) { NetworkFetchProducer.this.onFailure(fetchState, throwable); } @Override public void onCancellation() { NetworkFetchProducer.this.onCancellation(fetchState); } }); }
|
首先通过mNetworkFetcher创建了FetchState,mNetworkFetcher是网络层请求方式,如果没有特别指定,默认使用HttpUrlConnection,对应为HttpUrlConnectionNetworkFetcher。接下来调了fetch方法,正式发起网络请求,细节实现在mNetworkFetcher中。对应的回调响应为onResponse、onFailure与onCancellation,这里拿onResponse步骤进行分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| private void onResponse( FetchState fetchState, InputStream responseData, int responseContentLength) throws IOException { final PooledByteBufferOutputStream pooledOutputStream; //获取pooledOutputStream if (responseContentLength > 0) { pooledOutputStream = mPooledByteBufferFactory.newOutputStream(responseContentLength); } else { pooledOutputStream = mPooledByteBufferFactory.newOutputStream(); } final byte[] ioArray = mByteArrayPool.get(READ_SIZE); try { int length; while ((length = responseData.read(ioArray)) >= 0) { if (length > 0) { //将数据写入pooledOutputStream中 pooledOutputStream.write(ioArray, 0, length); //定时触发consumer回调 maybeHandleIntermediateResult(pooledOutputStream, fetchState); float progress = calculateProgress(pooledOutputStream.size(), responseContentLength); //进度更新 fetchState.getConsumer().onProgressUpdate(progress); } } mNetworkFetcher.onFetchCompletion(fetchState, pooledOutputStream.size()); //全部数据获取完毕,回调Consumer handleFinalResult(pooledOutputStream, fetchState); } finally { mByteArrayPool.release(ioArray); pooledOutputStream.close(); } }
|
通过上面的注释解析,主要的方法就两个:maybeHandleIntermediateResult与handleFinalResult,他们都是对网络请求的结果进行发送传递,他们的内部实现都是调用notifyConsumer方法进行回调通知。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| private void maybeHandleIntermediateResult( PooledByteBufferOutputStream pooledOutputStream, FetchState fetchState) { final long nowMs = SystemClock.uptimeMillis(); //时间间隔大于等于100毫秒进行通知 if (shouldPropagateIntermediateResults(fetchState) && nowMs - fetchState.getLastIntermediateResultTimeMs() >= TIME_BETWEEN_PARTIAL_RESULTS_MS) { fetchState.setLastIntermediateResultTimeMs(nowMs); fetchState.getListener() .onProducerEvent(fetchState.getId(), PRODUCER_NAME, INTERMEDIATE_RESULT_PRODUCER_EVENT); notifyConsumer( pooledOutputStream, fetchState.getOnNewResultStatusFlags(), fetchState.getResponseBytesRange(), fetchState.getConsumer()); } } private void handleFinalResult( PooledByteBufferOutputStream pooledOutputStream, FetchState fetchState) { Map<String, String> extraMap = getExtraMap(fetchState, pooledOutputStream.size()); ProducerListener listener = fetchState.getListener(); listener.onProducerFinishWithSuccess(fetchState.getId(), PRODUCER_NAME, extraMap); listener.onUltimateProducerReached(fetchState.getId(), PRODUCER_NAME, true); notifyConsumer( pooledOutputStream, Consumer.IS_LAST | fetchState.getOnNewResultStatusFlags(), fetchState.getResponseBytesRange(), fetchState.getConsumer()); }
|
它们最主要的区别是maybeHandleIntermediateResult是间隔性的调用notifyConsumer通知回调者。那么我们来看最终的回调通知方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| private void notifyConsumer( PooledByteBufferOutputStream pooledOutputStream, @Consumer.Status int status, @Nullable BytesRange responseBytesRange, Consumer<EncodedImage> consumer) { //对于PooledByteBuffer构建可关闭引用CloseableReference CloseableReference<PooledByteBuffer> result = CloseableReference.of(pooledOutputStream.toByteBuffer()); EncodedImage encodedImage = null; try { //保存到EncodedImage中 encodedImage = new EncodedImage(result); encodedImage.setBytesRange(responseBytesRange); //解析MetaData encodedImage.parseMetaData(); //回调通知 consumer.onNewResult(encodedImage, status); } finally { EncodedImage.closeSafely(encodedImage); CloseableReference.closeSafely(result); } }
|
首先对结果进行封装,保存到EncodedImage中,然后通过Consumer回调onNewResult方法将encodedImage传递到上一层的Producer系列,即之前所进过的流程,对其进行未解码的图片缓存与磁盘缓存操作。简单的说就是通过Consumer对结果进行一系列的解码、转换、缓存等操作,最终获取到Bitmap,传递给UI层进行图片更新设置。
HttpUrlConnectionNetworkFetcher的具体实现,有兴趣的可以自行查看源码,内部就是使用HttpUrlConnection进行网络资源请求与解析。
到这里整个的Producer调用流程就结束了,最终结果都会回到开篇分析的Result处理,AbstractProducerToDataSourceAdapter中的onNewResultImpl方法,通过super.setResult(result, isLast)传递结果与通知UI层更新UI。
总结
最后对Producer的整个调用流程做个总结,这里就直接使用源码中的注释调用链,主要可划分为三大部分,分别为:
swallow result if prefetch -> bitmap cache get ->
background thread hand-off -> multiplex -> bitmap cache -> decode -> multiplex ->
encoded cache -> disk cache -> (webp transcode) -> network fetch
分别对应Bitmap缓存获取、图片解码、未解码图片缓存获取、磁盘缓存获取与网络请求获取。