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请求的产生和消费,以及如何将结果传递给外部并相应的流程就打通了。下面再给一张图,哈哈。
最后
欢迎多多拍砖相关文章推荐
- ARM处理器的2种工作状态和7种工作模式
- oracle模糊查询
- SlidingMenu源码解析及简单应用案例
- 有梦就放开去追
- 使用注解实现AOP
- 程序包com.sun.image.codec.jpeg不存在 问题的完美解决
- 《如何及时处理你的坏心情》第二章:我们所担心的事情,99%是不会发生的
- ThreadPoolExecutor运转机制详解
- Linux-GLIBCXX版本过低导致编译错误--version `GLIBCXX_3.4.20' not found
- 各种 SDk
- Spring常用注解,自动扫描装配Bean
- 过滤dt中重复的记录
- 关于线程变量的应用
- 使用docker构建云服务器项目
- Codeforces 596A B C Codeforces Round #331 A B C
- LeetCode---First Bad Version
- jquery实践案例--验证电子邮箱
- 理解输入输出流
- Spring MVC 入门分析
- 关于mpls和ns3