/**
* 本文可以随意转载到任何网站或者App,
* BUT
* 转载也要按“基本法”,
* 请注明原文出处和作者
*/

官方源码地址

fresco官方高大上介绍(1)(注意:前方有堵墙)
fresco官方高大上介绍(2)(注意:前方有堵墙)
介绍:
上一篇大概介绍了fresco这个lib的整体结构和流程,这篇主要介绍fresco中关键的一部分--Producer
个人觉得,Producer基本是整个ImagePipeline module的核心,串联了整个图片读取的流程和各个细节(decode,resize等等)的处理,而且感觉整个设计上很有意思,读完感觉收益匪浅。
正文:
(分析主要是代码,相当枯燥~~~sigh)
以一次网络请求的例,进行分析,其他类型的请求,例如从cache中读取图片等,都差不多。
SimpleDraweeView#setController后,图片拉取的流程就开始了(详细流程可以参看上一篇的流程图)。忽略掉大部分细节,流程会来到(PipelineDraweeControllerBuilder.java):
  @Overrideprotected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest(ImageRequest imageRequest,Object callerContext,boolean bitmapCacheOnly) {if (bitmapCacheOnly) {return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext);} else {return mImagePipeline.fetchDecodedImage(imageRequest, callerContext);}}

这里就是开始图片拉取,转入到ImagePipeline核心流程。这里就是调用的ImagePipelinefetchDecodeImage方法,从名字看,意思就是“获取一张decode(解码)的图片”,其代码(ImagePipeline.java):
  /*** Submits a request for execution and returns a DataSource representing the pending decoded* image(s).* <p>The returned DataSource must be closed once the client has finished with it.* @param imageRequest the request to submit* @return a DataSource representing the pending decoded image(s)*/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);}}

这里有两个主要的函数:getDecodedImageProducerSequencesubmitFetchRequest
getDecodedImageProducerSequence的返回值就是一个Producer<CloseableReference<CloseableImage>>。该值作为参数,传到第二个函数submitFetchRequest中,先看submitFetchRequest
  private <T> DataSource<CloseableReference<T>> submitFetchRequest(Producer<CloseableReference<T>> producerSequence,ImageRequest imageRequest,ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit,Object callerContext) {try {ImageRequest.RequestLevel lowestPermittedRequestLevel =ImageRequest.RequestLevel.getMax(imageRequest.getLowestPermittedRequestLevel(),lowestPermittedRequestLevelOnSubmit);SettableProducerContext settableProducerContext = new SettableProducerContext(imageRequest,generateUniqueFutureId(),mRequestListener,callerContext,lowestPermittedRequestLevel,
/* isPrefetch */ false,imageRequest.getProgressiveRenderingEnabled() ||!UriUtil.isNetworkUri(imageRequest.getSourceUri()),imageRequest.getPriority());return CloseableProducerToDataSourceAdapter.create(producerSequence,settableProducerContext,mRequestListener);} catch (Exception exception) {return DataSources.immediateFailedDataSource(exception);}}

然后上面的create函数,就会一直到(AbstractProducerToDataSourceAdapter.java):
  protected AbstractProducerToDataSourceAdapter(Producer<T> producer,SettableProducerContext settableProducerContext,RequestListener requestListener) {mSettableProducerContext = settableProducerContext;mRequestListener = requestListener;mRequestListener.onRequestStart(settableProducerContext.getImageRequest(),mSettableProducerContext.getCallerContext(),mSettableProducerContext.getId(),mSettableProducerContext.isPrefetch());producer.produceResults(createConsumer(), settableProducerContext);}

到最后,submitFetchRequest会调用到Producer#produceResults方法,而这个producer就是前面那个getDecodedImageProducerSequence方法产生的,所以回头看这个最最关键的地方
getDecodedImageProducerSequenceProducerSequenceFactory.java的方法:
  /*** Returns a sequence that can be used for a request for a decoded image.** @param imageRequest the request that will be submitted* @return the sequence that should be used to process the request*/public Producer<CloseableReference<CloseableImage>> getDecodedImageProducerSequence(ImageRequest imageRequest) {Producer<CloseableReference<CloseableImage>> pipelineSequence =getBasicDecodedImageSequence(imageRequest);if (imageRequest.getPostprocessor() != null) {return getPostprocessorSequence(pipelineSequence);} else {return pipelineSequence;}}

从注释看,方法的意思就是返回一个用于请求decoded图片的sequence,而事实上,应该是返回一个Producer才对啊,
那为什么是强调是sequence Producer,而不是,仅仅就是一个Producer?

带着疑问继续看:
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)) {if (MediaUtils.isVideo(MediaUtils.extractMime(uri.getPath()))) {return getLocalVideoFileFetchSequence();} else {return getLocalImageFileFetchSequence();}} else if (UriUtil.isLocalContentUri(uri)) {return getLocalContentUriFetchSequence();} else if (UriUtil.isLocalAssetUri(uri)) {return getLocalAssetFetchSequence();} else if (UriUtil.isLocalResourceUri(uri)) {return getLocalResourceFetchSequence();} else if (UriUtil.isDataUri(uri)) {return getDataFetchSequence();} else {String uriString = uri.toString();if (uriString.length() > 30) {uriString = uriString.substring(0, 30) + "...";}throw new RuntimeException("Unsupported uri scheme! Uri is: " + uriString);}}

看代码可知道,就是根据ImageRequestUri,选择一个sequence Producer,我们这里假设是网络请求图片,所以选择的是图中红色方法getNetworkFetchSequence它也是返回一个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.*/private synchronized Producer<CloseableReference<CloseableImage>> getNetworkFetchSequence() {if (mNetworkFetchSequence == null) {mNetworkFetchSequence =newBitmapCacheGetToDecodeSequence(getCommonNetworkFetchToEncodedMemorySequence());}return mNetworkFetchSequence;}

先看红色代码,getCommonNetworkFetchToEncodedMemorySequence它也是返回一个Producer(可粗略看)
  /*** multiplex -> encoded cache -> disk cache -> (webp transcode) -> network fetch.*/private synchronized Producer<EncodedImage> getCommonNetworkFetchToEncodedMemorySequence() {if (mCommonNetworkFetchToEncodedMemorySequence == null) {Producer<EncodedImage> inputProducer =newEncodedCacheMultiplexToTranscodeSequence(mProducerFactory.newNetworkFetchProducer(mNetworkFetcher));mCommonNetworkFetchToEncodedMemorySequence =ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer);if (mResizeAndRotateEnabledForNetwork && !mDownsampleEnabled) {mCommonNetworkFetchToEncodedMemorySequence =mProducerFactory.newResizeAndRotateProducer(mCommonNetworkFetchToEncodedMemorySequence);}}return mCommonNetworkFetchToEncodedMemorySequence;}

再看,newEncodedCacheMultiplexToTranscodeSequence它也是返回一个Producer(可粗略看)
  /*** encoded cache multiplex -> encoded cache -> (disk cache) -> (webp transcode)* @param inputProducer producer providing the input to the transcode* @return encoded cache multiplex to webp transcode sequence*/private Producer<EncodedImage> newEncodedCacheMultiplexToTranscodeSequence(Producer<EncodedImage> inputProducer) {if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {inputProducer = mProducerFactory.newWebpTranscodeProducer(inputProducer);}inputProducer = mProducerFactory.newDiskCacheProducer(inputProducer);EncodedMemoryCacheProducer encodedMemoryCacheProducer =mProducerFactory.newEncodedMemoryCacheProducer(inputProducer);return mProducerFactory.newEncodedCacheKeyMultiplexProducer(encodedMemoryCacheProducer);}

选其中一个红色函数看,newDiskCacheProducer,它也是返回一个Producer(可粗略看)
  public DiskCacheProducer newDiskCacheProducer(Producer<EncodedImage> inputProducer) {return new DiskCacheProducer(mDefaultBufferedDiskCache,mSmallImageBufferedDiskCache,mCacheKeyFactory,inputProducer);}

好了,到此为止(列出的函数足够多了,晕~~~)
其实上面,一连串几个函数,如果有细心的留意,它们有一个特点,就是,每一个函数)都以 (上一个函数)产生的Producer作为参数进行传递
这样的设计,是不是有似曾相识的感觉,看下面的代码应该就能够了解得更深:
FileInputStream fileInputStream = new FileInputStream("/test.txt");InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);BufferedReader bufferedReader = new BufferedReader(inputSteamReader);

很熟悉了吧,可以把sequence Producer就看成是上面这样的一个逻辑~~~
那么这样做的作用是什么?我们选一个简单Producer来分析,就以DiskCacheProducer为例(留意代码绿色注释的描述)
 public DiskCacheProducer(BufferedDiskCache defaultBufferedDiskCache,BufferedDiskCache smallImageBufferedDiskCache,CacheKeyFactory cacheKeyFactory,Producer<EncodedImage> inputProducer) {mDefaultBufferedDiskCache = defaultBufferedDiskCache;mSmallImageBufferedDiskCache = smallImageBufferedDiskCache;mCacheKeyFactory = cacheKeyFactory;mInputProducer = inputProducer;}public void produceResults(final Consumer<EncodedImage> consumer,final ProducerContext producerContext) {ImageRequest imageRequest = producerContext.getImageRequest();
//如果diskcache disabled的话,那么直接执行maybeStartInputProducerif (!imageRequest.isDiskCacheEnabled()) {maybeStartInputProducer(consumer, consumer, producerContext);return;}final ProducerListener listener = producerContext.getListener();final String requestId = producerContext.getId();listener.onProducerStart(requestId, PRODUCER_NAME);final CacheKey cacheKey = mCacheKeyFactory.getEncodedCacheKey(imageRequest);final BufferedDiskCache cache =imageRequest.getImageType() == ImageRequest.ImageType.SMALL? mSmallImageBufferedDiskCache: mDefaultBufferedDiskCache;Continuation<EncodedImage, Void> continuation = new Continuation<EncodedImage, Void>() {//回调
      @Overridepublic Void then(Task<EncodedImage> task)throws Exception {//根据task是canceled,fault等状态决定如何执行if (task.isCancelled() ||(task.isFaulted() && task.getError() instanceof CancellationException)) {listener.onProducerFinishWithCancellation(requestId, PRODUCER_NAME, null);consumer.onCancellation();} else if (task.isFaulted()) {listener.onProducerFinishWithFailure(requestId, PRODUCER_NAME, task.getError(), null);//出错了,就调用maybeStartInputProducer
          maybeStartInputProducer(consumer,new DiskCacheConsumer(consumer, cache, cacheKey),producerContext);} else {EncodedImage cachedReference = task.getResult();if (cachedReference != null) {listener.onProducerFinishWithSuccess(requestId,PRODUCER_NAME,getExtraMap(listener, requestId, true));consumer.onProgressUpdate(1);consumer.onNewResult(cachedReference, true);cachedReference.close();} else {//没有结果,就调用maybeStartInputProducer
            listener.onProducerFinishWithSuccess(requestId,PRODUCER_NAME,getExtraMap(listener, requestId, false));maybeStartInputProducer(consumer,new DiskCacheConsumer(consumer, cache, cacheKey),producerContext);}}return null;}};AtomicBoolean isCancelled = new AtomicBoolean(false);final Task<EncodedImage> diskCacheLookupTask =cache.get(cacheKey, isCancelled);
//执行task,task其实就是从缓存中取结果,执行后,前面的continuation就会被回调
    diskCacheLookupTask.continueWith(continuation);subscribeTaskForRequestCancellation(isCancelled, producerContext);}//调用mInputProducer的produceResults private void maybeStartInputProducer(Consumer<EncodedImage> consumerOfDiskCacheProducer,Consumer<EncodedImage> consumerOfInputProducer,ProducerContext producerContext) {if (producerContext.getLowestPermittedRequestLevel().getValue() >=ImageRequest.RequestLevel.DISK_CACHE.getValue()) {consumerOfDiskCacheProducer.onNewResult(null, true);return;}mInputProducer.produceResults(consumerOfInputProducer, producerContext);}

从前面知道,当开始拉取图片的时候,Producer#produceResult开始执行,注释标出了关键的步骤,从这些步骤可以看出,其实DiskCacheProducer拉取图片时,做的任务大概就是:先看Diskcache中是否有缓存的图片,如果有,就直接返回缓存,如果没有,就用inputProducer来处理
然后,inputProducer处理完结果会怎样呢?它处理的结果会在consumer中接收到,上面的例子代码对应的就是DiskCacheConsumer(留意绿色注释)
  /*** Consumer that consumes results from next producer in the sequence.** <p>The consumer puts the last result received into disk cache, and passes all results (success* or failure) down to the next consumer.*/private class DiskCacheConsumer extends DelegatingConsumer<EncodedImage, EncodedImage> {private final BufferedDiskCache mCache;private final CacheKey mCacheKey;private DiskCacheConsumer(final Consumer<EncodedImage> consumer,final BufferedDiskCache cache,final CacheKey cacheKey) {super(consumer);mCache = cache;mCacheKey = cacheKey;}//inputProducer的结果会从这里返回,即newResult
    @Overridepublic void onNewResultImpl(EncodedImage newResult, boolean isLast) {//返回的结果加入cache中if (newResult != null && isLast) {mCache.put(mCacheKey, newResult);}//回调上一层procducer传进来的consumer
      getConsumer().onNewResult(newResult, isLast);}}

到这里,应该就大概明白这个sequence Producer的作用了,所谓sequence Producer,其实就是一层层的Producer不断的嵌套连接起来,完成同一个任务,而每一个Producer都相互独立,完成各自任务;同时,Producer间产生的结果,也会相互传递,互为表里。可以称其为“Producer链”,但是“Producer链”本身被抽象成一个Producer,那么对于上层来看,这样一个复杂的处理逻辑就被隐藏起来了,变得更加容易理解。
sequence Producer功能极其强大,不同的Producer的组合,产生了很多不同的效果,对于代码的扩展性,可复用性和灵活性都有很大好处。
例如,MultiplexProducer
注释:
/**
* Producer for combining multiple identical requests into a single request.
*
* <p>Requests using the same key will be combined into a single request. This request is only
* cancelled when all underlying requests are cancelled, and returns values to all underlying
* consumers. If the request has already return one or more results but has not finished, then
* any requests with the same key will have the most recent result returned to them immediately.
*
* @param <K> type of the key
* @param <T> type of the closeable reference result that is returned to this producer
*/
@ThreadSafe
public abstract class MultiplexProducer<K, T extends Closeable> implements Producer<T>

理解为,多路复用Producer(什么鬼东西?),其实就是将相同的任务合并为一个,例如相同url的重复请求,如何做到的,关键代码(主要看注释):
  @Overridepublic void produceResults(Consumer<T> consumer, ProducerContext context) {K key = getKey(context);Multiplexer multiplexer;boolean createdNewMultiplexer;
// We do want to limit scope of this lock to guard only accesses to mMultiplexers map.
// However what we would like to do here is to atomically lookup mMultiplexers, add new
// consumer to consumers set associated with the map's entry and call consumer's callback with
// last intermediate result. We should not do all of those things under this lock.do {createdNewMultiplexer = false;synchronized (this) {//根据key获得多路复用器,当缓存没有的时候,才create一个,不然直接忽略multiplexer = getExistingMultiplexer(key);if (multiplexer == null) {multiplexer = createAndPutNewMultiplexer(key);createdNewMultiplexer = true;}}
// addNewConsumer may call consumer's onNewResult method immediately. For this reason
// we release "this" lock. If multiplexer is removed from mMultiplexers in the meantime,
// which is not very probable, then addNewConsumer will fail and we will be able to retry.} while (!multiplexer.addNewConsumer(consumer, context));//如果前面没有创建,也就是存在缓存的多路复用器,那么就不会调用startInputProducerIfHasAttachedConsumers,然后inputProducer就不起作用了,这样,就起到合并请求的作用if (createdNewMultiplexer) {multiplexer.startInputProducerIfHasAttachedConsumers();}}

不同的功能Producer还有很多,例如对图片进行resize和rotate的ResizeAndRotateProducer, 异步执行任务的ThreadHandoffProducer等等,如此灵活的实现,得益于sequence Factory这种设计。
总结
ImagePipeline的核心Producer,通过sequence的形式,很好的串联了整个图片网络读取,缓存,bitmap处理等流程,通过优秀的设计,保证的代码高扩展性高可复用性高灵活性
这种设计刚好对应就是“pipeline”这个词的含义,就如现代的pipelined CPU一样,把对指令的处理,拆分成多个stage,同时输入输出相互依赖和协作,共同完成一个任务。
~~~文卒~~~

转载于:https://www.cnblogs.com/chiefhsing/p/5125950.html

【Android】Fresco图片加载框架(二)————Producer相关推荐

  1. Android Glide图片加载框架(二)源码解析之into()

    文章目录 一.前言 二.源码解析 1.into(ImageView) 2.GlideContext.buildImageViewTarget() 3.RequestBuilder.into(Targe ...

  2. Android Glide图片加载框架(二)源码解析之load()

    文章目录 一.前言 二.源码分析 1.load() Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图片加载框架(二)源 ...

  3. Android Glide图片加载框架(二)源码解析之with()

    文章目录 一.前言 二.如何阅读源码 三.源码解析 1.with() Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图 ...

  4. Android Glide图片加载框架(一)基本用法

    文章目录 一.前言 二.简介 三.基本用法 第一步:调用 Glide.with() 方法创建加载图片的实例 第二步:调用 load() 方法指定待加载的图片资源 第三步:调用 into() 方法绑定显 ...

  5. (三) 技术选型 1.项目框架模式:MVP(得分点);注意:分包分层,避免内存泄漏; 2.图片加载:Fresco图片加载框架; 3.网络加载框架:retrofit;使用Retrofit+RxJ

    首先呢    先把业务逻辑需求讲一下  大致思路都是根据自己所想的去做,下面是我个人做的一个小model,希望能帮到有需要的人 业务逻辑需求 1.MVP分包分层:Model.View.Presente ...

  6. Fresco图片加载框架的介绍,相关开源库以及工具类的封装

    Fresco图片加载框架的介绍,相关开源库以及工具类的封装 本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发. 简介 Fresco 是Facebook开源的安卓上的 ...

  7. Android Glide图片加载框架(四)回调与监听

    文章目录 Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图片加载框架(二)源码解析之with() Android Gl ...

  8. Android Glide图片加载框架(三)缓存机制

    文章目录 一.缓存简介 二.缓存用法 内存缓存方式 磁盘缓存方式 三.缓存KEY 四.内存缓存 内存缓存流程 五.磁盘缓存 磁盘缓存流程 Android Glide图片加载框架系列文章 Android ...

  9. Fresco图片加载框架使用方法完全指南

    简介 Fresco 是Facebook开源的安卓上的图片加载框架,也可以说是至今为止安卓上最强大的图片加载框架. 相对于其他几个图片加载框架,Fresco主要的优点在于更好的内存管理和更强大的功能,更 ...

  10. Android Glide 图片加载框架解析

    在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载框架,作者是  bumptech,这个库被广泛的应用在 Google 开源项目中,包括 2014 年 Google I/O ...

最新文章

  1. trainer setup_Detectron2源码阅读笔记-(一)Configamp;Trainer
  2. qq分享组件 android,移动端,分享插件
  3. Go语言(Golang)约瑟夫游戏(Joseph)
  4. 每日两SQL(6),欢迎交流~
  5. 23个机器学习项目,助你成为人工智能大咖
  6. c 向html页面传值,html页面之间的传值,获取元素和方法的调用
  7. 32 - I. 从上到下打印二叉树
  8. php外边框样式,CSS中的边框样式
  9. 如何测试网站服务器mysql数据库连接,如何测试网站服务器mysql数据库
  10. Java实现视频加密及播放
  11. 新手快速使用Monkey测试工具的方法
  12. oracle的解释计划,oracle解释执行计划-Oracle
  13. 考育婴师看什么书?中级育婴师需要备考多久?
  14. vhs预设_vhs vs beta原始格式大战的故事
  15. C语言 将一个3*3的矩阵转置,用函数和指针实现
  16. uniapp中使用iconfont多色图标
  17. 智工教育:一级建造师《公路实务》考前必背知识点
  18. 关于glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLfloat z)的参数的一些理解
  19. ESD和TVS管的区别
  20. C中strchr()函数用法

热门文章

  1. json文件解析工具_JSON格式的文本文件,怎么解析不成功?
  2. 隐藏a标签seo_百度SEO网站整体优化方案 - 蜘蛛池博客
  3. nginx防火墙在哪设置_Nginx 基本使用介绍
  4. 服务器说你注册过多,为什么我的世界服务器说此用户名已被注册我都换了很多用户了都没用 爱问知识人...
  5. 新乡学院2019计算机报名,新乡学院2019年招生章程
  6. 北京交通大学计算机学院篮球,院际杯篮球赛|男篮小组赛第四轮战报
  7. 正弦函数_题型和解析 | 三角函数(补充)
  8. mysql远程访问权限_MYSQL开启远程访问权限的方法
  9. android drawable 对象,Android Drawable开发简介
  10. 修改js版本_啥都学点之使用nvm安装Node.js并实现Node.js多版本管理