您的位置:首页 > 其它

Fresco正传(5):请求产生和发出请求

2015-11-16 11:43 232 查看

前言

请求产生和请求发出的内容,还是很复杂的,这里需要了解一些背景知识。

首先是
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()
方法就是发送请求的地方,跟进去看看做了什么:

计算出当前图片最低的请求级别

获得请求信息的上下文

根据创建的SettableProducerContext,再利用Producer和DataSource的适配器,创建一个DataSource。

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请求的产生和消费,以及如何将结果传递给外部并相应的流程就打通了。下面再给一张图,哈哈。



最后

欢迎多多拍砖
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: