【Android】Fresco图片加载框架(二)————Producer
/** * 本文可以随意转载到任何网站或者App, * BUT * 转载也要按“基本法”, * 请注明原文出处和作者 */
官方源码地址
@Overrideprotected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest(ImageRequest imageRequest,Object callerContext,boolean bitmapCacheOnly) {if (bitmapCacheOnly) {return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext);} else {return mImagePipeline.fetchDecodedImage(imageRequest, callerContext);}}
/*** 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);}}
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);}}
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);}
/*** 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;}}
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);}}
/*** 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;}
/*** 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;}
/*** 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);}
public DiskCacheProducer newDiskCacheProducer(Producer<EncodedImage> inputProducer) {return new DiskCacheProducer(mDefaultBufferedDiskCache,mSmallImageBufferedDiskCache,mCacheKeyFactory,inputProducer);}
FileInputStream fileInputStream = new FileInputStream("/test.txt");InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);BufferedReader bufferedReader = new BufferedReader(inputSteamReader);
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);}
/*** 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);}}
/** * 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>
@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();}}
转载于:https://www.cnblogs.com/chiefhsing/p/5125950.html
【Android】Fresco图片加载框架(二)————Producer相关推荐
- Android Glide图片加载框架(二)源码解析之into()
文章目录 一.前言 二.源码解析 1.into(ImageView) 2.GlideContext.buildImageViewTarget() 3.RequestBuilder.into(Targe ...
- Android Glide图片加载框架(二)源码解析之load()
文章目录 一.前言 二.源码分析 1.load() Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图片加载框架(二)源 ...
- Android Glide图片加载框架(二)源码解析之with()
文章目录 一.前言 二.如何阅读源码 三.源码解析 1.with() Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图 ...
- Android Glide图片加载框架(一)基本用法
文章目录 一.前言 二.简介 三.基本用法 第一步:调用 Glide.with() 方法创建加载图片的实例 第二步:调用 load() 方法指定待加载的图片资源 第三步:调用 into() 方法绑定显 ...
- (三) 技术选型 1.项目框架模式:MVP(得分点);注意:分包分层,避免内存泄漏; 2.图片加载:Fresco图片加载框架; 3.网络加载框架:retrofit;使用Retrofit+RxJ
首先呢 先把业务逻辑需求讲一下 大致思路都是根据自己所想的去做,下面是我个人做的一个小model,希望能帮到有需要的人 业务逻辑需求 1.MVP分包分层:Model.View.Presente ...
- Fresco图片加载框架的介绍,相关开源库以及工具类的封装
Fresco图片加载框架的介绍,相关开源库以及工具类的封装 本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发. 简介 Fresco 是Facebook开源的安卓上的 ...
- Android Glide图片加载框架(四)回调与监听
文章目录 Android Glide图片加载框架系列文章 Android Glide图片加载框架(一)基本用法 Android Glide图片加载框架(二)源码解析之with() Android Gl ...
- Android Glide图片加载框架(三)缓存机制
文章目录 一.缓存简介 二.缓存用法 内存缓存方式 磁盘缓存方式 三.缓存KEY 四.内存缓存 内存缓存流程 五.磁盘缓存 磁盘缓存流程 Android Glide图片加载框架系列文章 Android ...
- Fresco图片加载框架使用方法完全指南
简介 Fresco 是Facebook开源的安卓上的图片加载框架,也可以说是至今为止安卓上最强大的图片加载框架. 相对于其他几个图片加载框架,Fresco主要的优点在于更好的内存管理和更强大的功能,更 ...
- Android Glide 图片加载框架解析
在泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载框架,作者是 bumptech,这个库被广泛的应用在 Google 开源项目中,包括 2014 年 Google I/O ...
最新文章
- trainer setup_Detectron2源码阅读笔记-(一)Configamp;Trainer
- qq分享组件 android,移动端,分享插件
- Go语言(Golang)约瑟夫游戏(Joseph)
- 每日两SQL(6),欢迎交流~
- 23个机器学习项目,助你成为人工智能大咖
- c 向html页面传值,html页面之间的传值,获取元素和方法的调用
- 32 - I. 从上到下打印二叉树
- php外边框样式,CSS中的边框样式
- 如何测试网站服务器mysql数据库连接,如何测试网站服务器mysql数据库
- Java实现视频加密及播放
- 新手快速使用Monkey测试工具的方法
- oracle的解释计划,oracle解释执行计划-Oracle
- 考育婴师看什么书?中级育婴师需要备考多久?
- vhs预设_vhs vs beta原始格式大战的故事
- C语言 将一个3*3的矩阵转置,用函数和指针实现
- uniapp中使用iconfont多色图标
- 智工教育:一级建造师《公路实务》考前必背知识点
- 关于glRotatef(GLfloat angle,GLfloat x,GLfloat y,GLfloat z)的参数的一些理解
- ESD和TVS管的区别
- C中strchr()函数用法
热门文章
- json文件解析工具_JSON格式的文本文件,怎么解析不成功?
- 隐藏a标签seo_百度SEO网站整体优化方案 - 蜘蛛池博客
- nginx防火墙在哪设置_Nginx 基本使用介绍
- 服务器说你注册过多,为什么我的世界服务器说此用户名已被注册我都换了很多用户了都没用 爱问知识人...
- 新乡学院2019计算机报名,新乡学院2019年招生章程
- 北京交通大学计算机学院篮球,院际杯篮球赛|男篮小组赛第四轮战报
- 正弦函数_题型和解析 | 三角函数(补充)
- mysql远程访问权限_MYSQL开启远程访问权限的方法
- android drawable 对象,Android Drawable开发简介
- 修改js版本_啥都学点之使用nvm安装Node.js并实现Node.js多版本管理