请求产生和请求发出的内容,还是很复杂的,这里需要了解一些背景知识。
首先是ImagePipeline
的介绍,其实不用我说,在官网上已经给出了基本的介绍:ImagePipeline介绍
其次是Producer
模式,在Fresco中请求产生这块,用到了大量的这种概念,将网络数据的获取,磁盘缓存获取,内存缓存获取,解码,编码和图片的变换等等的处理,分为模块处理,并以倒叙的方式联合再一起调用。显得格外的高大上,就是初次见有点难以理解。
public interface Producer<T> {
void produceResults(Consumer<T> consumer, ProducerContext context);
}
Producer
作为一个行为,表示的是生产结果。有了结果就要处理,而produceResults()
方法就代表处理结果,那么是谁处理结果我们不知道,所以就由参数传入,故而就有了消费者Consumer
。
而Producer
的处理模式在Fresco中表现的也比较奇特,由于网络数据的获取,磁盘缓存获取,内存缓存获取,解码,编码和图片等这些操作是一个流程处理,那么如何将流程性的东西和Producer
结合起来呢?
为了成为一个链式,会有如下的代码模式:
public class XXProducer implements Producer {
private final Producer mInputProducer;
public XXProducer (Producer inputProducer) {
mInputProducer = inputProducer;
}
@Override
public void produceResults(Consumer consumer, ProducerContext context) {
mInputProducer.produceResults(consumer, context);
}
}
接收一个外部的生产者,并在自身处理结果方法的最后调用外部生产者处理结果的方法。
这样看似先创建外部的生产者,但是实际上最后才调用外部的生产者。所以Fresco实例的创建和反向调用就好像这个样子:
明白了这一点,就开始正式的分析吧。
先回顾下前文,分析到了PipelineDraweeControllerBuilder.getDataSourceForRequest()
方法。
@Override
protected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest(
ImageRequest imageRequest,
Object callerContext,
boolean bitmapCacheOnly) {
if (bitmapCacheOnly /*false*/) {
return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext);
} else {
// 抓取图片
return mImagePipeline.fetchDecodedImage(imageRequest, callerContext);
}
}
由于bitmapCacheOnly
为false,所以调用的是fetchDecodeImage()
方法,而本片文章分析的重点就在这个方法了。
public DataSource<CloseableReference<CloseableImage>> fetchDecodedImage(
ImageRequest imageRequest,
Object callerContext) {
try {
// 产生请求
Producer<CloseableReference<CloseableImage>> producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
// 发送请求,并返回数据源
return submitFetchRequest(
producerSequence,
imageRequest,
ImageRequest.RequestLevel.FULL_FETCH,
callerContext);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
看一下这句代码:
Producer<CloseableReference<CloseableImage>> producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
大概的意思是,获取用于图片解码的生产者序列。注意是序列,这说明该操作内部有很多的操作单元。而这其中又分为两种,一个是基础的请求序列,另一个是后处理器。
public Producer<CloseableReference<CloseableImage>> getDecodedImageProducerSequence(
ImageRequest imageRequest) {
// 获取基础解码序列请求
Producer<CloseableReference<CloseableImage>> pipelineSequence = getBasicDecodedImageSequence(imageRequest);
// 后处理器处理
if (imageRequest.getPostprocessor() != null) {
return getPostprocessorSequence(pipelineSequence);
} else {
return pipelineSequence;
}
}
我们关注的重点自然是基础请求序列,后处理器后续有机会再说。继续跟到getBasicDecodedImageSequence()
中。
private Producer<CloseableReference<CloseableImage>> getBasicDecodedImageSequence(
ImageRequest imageRequest) {
Preconditions.checkNotNull(imageRequest);
Uri uri = imageRequest.getSourceUri();
Preconditions.checkNotNull(uri, "Uri is null.");
if (UriUtil.isNetworkUri(uri)) {
// 获取网络请求序列
return getNetworkFetchSequence();
} else if (UriUtil.isLocalFileUri(uri)) {
......
.....
省略N多代码
}
}
此处分支判断的根据是Uri的类型。网络请求的序列最为复杂,这里分析该分支。
private synchronized Producer<CloseableReference<CloseableImage>> getNetworkFetchSequence() {
if (mNetworkFetchSequence == null) {
mNetworkFetchSequence =
// 2,内存缓存解码序列
newBitmapCacheGetToDecodeSequence(
// 1,网络抓取,并解码到内存序列
getCommonNetworkFetchToEncodedMemorySequence());
}
return mNetworkFetchSequence;
}
还记得在前言中分析的Produer
模式的工作原理吗?这里先创建的网络请求编码序列,并将其传入到内存缓存编码序列中去,也就是说最后的时候才会调用网络请求编码序列。
这里简单看一下getCommonNetFetchToEncodedMemorySequence()
方法,其中做了:
/** * 通用的网络到编码内存的图片获取方式 * multiplex -> encoded cache -> disk cache -> (webp transcode) -> network fetch. */
private synchronized Producer<EncodedImage> getCommonNetworkFetchToEncodedMemorySequence() {
if (mCommonNetworkFetchToEncodedMemorySequence == null) {
Producer<EncodedImage> inputProducer = newEncodedCacheMultiplexToTranscodeSequence(
// 先生成一个网络获取的producer
mProducerFactory.newNetworkFetchProducer(mNetworkFetcher));
// 传递给内存编码的producer
mCommonNetworkFetchToEncodedMemorySequence = ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer);
if (mResizeAndRotateEnabledForNetwork && !mDownsampleEnabled) {
// 如果允许网络图片的重新设置大小和旋转,再传递给用于处理旋转和重新设置大小的producer
mCommonNetworkFetchToEncodedMemorySequence = mProducerFactory.newResizeAndRotateProducer(mCommonNetworkFetchToEncodedMemorySequence);
}
}
return mCommonNetworkFetchToEncodedMemorySequence;
}
经过newNetworkFetchProducer()
方法,跟踪到NetworkFetcherProducer
类中,类中的producerResults()
方法如下。
@Override
public void produceResults(Consumer<EncodedImage> consumer, ProducerContext context) {
context.getListener()
.onProducerStart(context.getId(), PRODUCER_NAME);
final FetchState fetchState = mNetworkFetcher.createFetchState(consumer, context);
mNetworkFetcher.fetch(
fetchState, new NetworkFetcher.Callback() {
@Override
public void onResponse(InputStream response, int responseLength) throws IOException {
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);
}
});
}
在这里处理请求结果的回调。在NetworkFetchProducer
类的onResponse()
方法中,也是进行一系列的流读取操作。这个类就暂时分析到这里。
再回到getNetworkFetchSequence()
方法,进入到newBitmapCacheGetToDecodeSequence()
方法中。
private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToDecodeSequence(
Producer<EncodedImage> inputProducer) {
DecodeProducer decodeProducer = mProducerFactory.newDecodeProducer(inputProducer);
// 将生产者作为参数传递给下一个生产者
return newBitmapCacheGetToBitmapCacheSequence(decodeProducer);
}
依旧是创建生产者,传递生产者。继续跟到newBitmapCacheGetToBitmapCacheSequence()
方法中。
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);
// 内存缓存请求生产者
return mProducerFactory.newBitmapMemoryCacheGetProducer(threadHandoffProducer);
}
在ImagePipeline介绍中,我们了解到任何一个请求都是先从内存缓存开始的。那么,此处就应该是最内存的生产者。
public class BitmapMemoryCacheGetProducer extends BitmapMemoryCacheProducer {
@VisibleForTesting static final String PRODUCER_NAME = "BitmapMemoryCacheGetProducer";
public BitmapMemoryCacheGetProducer(
MemoryCache<CacheKey, CloseableImage> memoryCache,
CacheKeyFactory cacheKeyFactory,
Producer<CloseableReference<CloseableImage>> inputProducer) {
super(memoryCache, cacheKeyFactory, inputProducer);
}
@Override
protected Consumer<CloseableReference<CloseableImage>> wrapConsumer(
final Consumer<CloseableReference<CloseableImage>> consumer,
final CacheKey cacheKey) {
// since this cache is read-only, we can pass our consumer directly to the next producer
return consumer;
}
@Override
protected String getProducerName() {
return PRODUCER_NAME;
}
}
进入到该类后,发现并没有什么实质性的内容,我们跟到父类中。在produceResults()
方法,发现了很多逻辑,其中在最后一句调用下一个生产者的produceResults()
方法。其中还用到了代理设计模式:
// 在这里用到了代理设计模式,因为呢,每个producer都会调用consumer的方法,但是不同的producer需要在原有consumer
// 的基础上处理自己的一些逻辑,这里呢?就需要将原来的consumer进行代理,调用时,先处理自己的逻辑,然后调用原有consumer的相关方法即可
Consumer<CloseableReference<CloseableImage>> wrappedConsumer = wrapConsumer(consumer, cacheKey);
listener.onProducerFinishWithSuccess(
requestId,
getProducerName(),
listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
mInputProducer.produceResults(wrappedConsumer, producerContext);
有了下一步调用的produceResults()
方法,那么哪里才是第一次调用produceResults()
的地方呢? 这个地方肯定就是这一系列请求最先开始的地方。
带着这样的疑问我们进入下一个问题,如何发出请求的。
public DataSource<CloseableReference<CloseableImage>> fetchDecodedImage(
ImageRequest imageRequest,
Object callerContext) {
try {
Producer<CloseableReference<CloseableImage>> producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
// 发送请求,并返回数据源
return submitFetchRequest(
producerSequence,
imageRequest,
ImageRequest.RequestLevel.FULL_FETCH,
callerContext);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
不用我说多,submitFetchRequest()
方法就是发送请求的地方,跟进去看看做了什么:
private <T> DataSource<CloseableReference<T>> submitFetchRequest(
Producer<CloseableReference<T>> producerSequence,
ImageRequest imageRequest,
ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit,
Object callerContext) {
try {
// 计算出当前当前图片的最低的请求级别
// 根据前一个方法的调用的参数,得知是与最低级别的ImageRequest.RequestLevel.BITMAP_MEMORY_CACHE,所以在提交请求时最低级别就是我们在请求中设置的级别
ImageRequest.RequestLevel lowestPermittedRequestLevel =
ImageRequest.RequestLevel.getMax(
imageRequest.getLowestPermittedRequestLevel(),
lowestPermittedRequestLevelOnSubmit);
// ProducerContext也是请求信息的一个上下文,这里包含了所有在producer处理过程中需要得知的信息,例如图片的请求信息,请求的优先级,请求的id,是否要预处理等等.
SettableProducerContext settableProducerContext = new SettableProducerContext(
imageRequest,
generateUniqueFutureId(),
mRequestListener,
callerContext,
lowestPermittedRequestLevel,
/* isPrefetch */ false,
imageRequest.getProgressiveRenderingEnabled() ||
!UriUtil.isNetworkUri(imageRequest.getSourceUri()),
imageRequest.getPriority());
// 根据创建的settableProducerContext,再将利用Producer和DataSource中间的适配器,创建了一个DataSource(需要理解的核心部分)
return CloseableProducerToDataSourceAdapter.create(
producerSequence,
settableProducerContext,
mRequestListener);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
进入 可关闭的生产者到数据源的适配器CloseableProducerToDataSourceAdapter
类中,发现其中没有什么重要的逻辑,提供了几个安全关闭结果的方法。
继续跟踪到父类中,再起构造方法中发现调用了produceResult()
。
producer.produceResults(createConsumer(), settableProducerContext);
那么问题来了,这个producer是谁? 其实不用我多说,你们也能猜到,肯定是内存缓存生产者BitmapMemoryCacheProducer
类。由这里开始,就一层一层的向外调用包裹的生产者,直到最后的网络请求。
生产者第一次调用的地方被找到了,那么消费结果的消费者也出现了:createConsumer()
,在方法内部创建BaseConsumer
匿名内部类的实例,并将回调结果传递给AbstractProducerToDataSourceAdapter
类内的方法。
当结果产生时会调用onNewResultImple()
方法。
protected void onNewResultImpl(@Nullable T result, boolean isLast) {
// 向外通知结果
if (super.setResult(result, isLast)) {
if (isLast) {
mRequestListener.onRequestSuccess(
mSettableProducerContext.getImageRequest(),
mSettableProducerContext.getId(),
mSettableProducerContext.isPrefetch());
}
}
}
看一下AbstractProducerToDataSourceAdapter
类的继承体系你会发现其继承AbstractDataSource
,而AbstractDataSource
类实现了DataSource
接口,代表其也是个被观察者。
观察者在哪里? 被观察者如何将结果通知给观察者呢?
不知道你是否还记得BaseDataSubscriber
抽象类呢? 在AbstractDraweeController
类的submitRequest()
方法中,构建了BaseDataSubscriber()
类的的实例,这里用于处理观察者传递出来的结果。
final DataSubscriber<T> dataSubscriber =
new BaseDataSubscriber<T>() {
@Override
public void onNewResultImpl(DataSource<T> 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();
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<T> dataSource) {
onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true);
}
@Override
public void onProgressUpdate(DataSource<T> dataSource) {
boolean isFinished = dataSource.isFinished();
float progress = dataSource.getProgress();
onProgressUpdateInternal(id, dataSource, progress, isFinished);
}
};
找到了观察者,那么如何被观察者如何将结果通知给观察者呢?
回到被观察者AbstractProducerToDataSourceAdapter
类的onNewResultImple()
方法,其中发现调用了如下代码,将获得的结果通知给外部:
super.setResult(result, isLast);
跟踪到父类中看看,在方法内部调用了notifyDataSubscribers()
方法,通知所有的观察者:
protected boolean setResult(@Nullable T value, boolean isLast) {
boolean result = setResultInternal(value, isLast);
if (result) {
notifyDataSubscribers();
}
return result;
}
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);
}
}
这样,整个Fresco请求的产生和消费,以及如何将结果传递给外部并相应的流程就打通了。下面再给一张图,哈哈。
欢迎多多拍砖