盒子
盒子
文章目录
  1. Producer
  2. Result处理
  3. Producer的兄弟姐妹
    1. Bitmap缓存系列Producer
    2. 未解码图片的内存缓存与磁盘缓存系列Producer
    3. 网络请求Producer
  4. 总结

Fresco源码分析之Producer

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缓存获取、图片解码、未解码图片缓存获取、磁盘缓存获取与网络请求获取。

支持一下
赞赏是一门艺术