Fresco源码赏析之后台获取流程
2016-05-26 16:52
211 查看
在Fresco源码赏析 之基本流程中把setImageUrl()方法调用后是如何自动完成剩下的事情的步骤的流程理了一遍,基本可以知道了大体的整个流程,看这个点这里:
点击打开链接
在Fresco源码赏析 之图片显示流程 把获取数据后是如何完成ui的刷新、Fresco封装的控件是如何封装管理drawable简单了说清楚了,看这个文点击这里:
点击打开链接
本文主要是最后的一篇分析了,主要是再具体看看Fresco启动后台获取数据的流程,在Fresco源码赏析 之基本流程中并没有讲的很清楚,源码还是比较复杂的,可能分析得不到位,欢迎交流学习。
转载请注明出处:http://blog.csdn.net/u014614038/article/details/51507236
根据前面两文,知道了一点是,Fresco获取数据的过程分成了不同的producer进行不同的任务,他们之间通过consumer进行数据传递,这个有的类似与职责链模式,不同的producer有不同的职责,它复杂找缓存、它负责编码、它负责获取网络数据、、等等。我简单画了个图:
这个是简单大概的图,可以概括说明了Fresco获取数据的整个流程思路,事实上会比这个复杂多,如图示,每个producer其实就是复杂一个职责的工作,有些是获取缓存数据,也有些进行编码、进行缓存、进行网络获取等等,一开始请求数据后应该是去缓存获取producer1那里请求数据,有就直接返回不会进行下面的操作,没有缓存获取producer1会交给下一个producer处理,以此类推下去,最终不得已只好去获取网络数据,这期间包含一系列的producer,形成一条职责链,完成了整个获取数据的过程。
我们看看请求数据的入口:
我们略过跳的获取网络数据的那个方法里,具体请看在Fresco源码赏析 之基本流程:
这里返回的是一个网络获取的producer,事实上是多个producer的链,这里返回的只是链头而已,最终从链头走到链为,这个过程可能中断也可能完全走完,但是从代码上看的画,这个链肯定是完整 ,newBitmapCacheGetToDecodeSequence返回的是一个producer,它的下个pruducer是getCommonNetworkFetchToEncodedMemorySequence()返回的pruducer,我们具体看看这两个方法:
先看前一个:
看到方法传入的参数没有,nextProducer,就是说传入的producer是下一个职责负责的producer,就是当前producer完成后如果有必要就交给下个producer处理,比如找了发现没有缓存数据,那么就交给图片数据编码的producer处理,它就不管了。同理mProducerFactory传入的参数名也叫nextproducer,就是它创建的那个producer的下一个producer就是传入的那个,这样下来就形成了一个完整的链了。
看后一个方法:
其实这个mNetworkFetchProducer才是最后发起网络请求进行数据获取的producer,这样标志一下。
根据上面的两个方法,我简单整理了一下整个职责链:
是不是感觉有的怪,事实上有些producer不是在上一个producer传递下来时执行的,它是在数据返回时执行的比如编码、转码之类的,这个实现就是通过consumer实现的,consumer说是传递在整个链里面,实现它在必要的producer中会重新创建一个进行对数据返回时的拦截并进行相应的处理,如缓存producer,没有缓存的时候应该是去获取网络数据,进行这步有什么意义?其实它在这里做的缓存处理只是在consumer数据回调时对数据进行缓存,它的做法就是创建一个新的consumer,将新的consumer传递到下一个producer,最终数据通过这个新的consumer返回回来,它获取到数据后进行缓存处理,处理完通过就的consumer返回回去。我个人觉得这样的设计非常巧妙,让所有的producer衔接起来。
下面是缓存producer在上个producer传递下来执行的操作:
所以去实际上本身的职责工作是在数据返回时才进行,其他有些producer也是类似的做法。
好啦,producer的流程大概说明白了,其每个producer具体实现就不说了,毕竟太多了,根据这个思路去看很容易就看明白了。
转载请注明出处:http://blog.csdn.net/u014614038/article/details/51507236
点击打开链接
在Fresco源码赏析 之图片显示流程 把获取数据后是如何完成ui的刷新、Fresco封装的控件是如何封装管理drawable简单了说清楚了,看这个文点击这里:
点击打开链接
本文主要是最后的一篇分析了,主要是再具体看看Fresco启动后台获取数据的流程,在Fresco源码赏析 之基本流程中并没有讲的很清楚,源码还是比较复杂的,可能分析得不到位,欢迎交流学习。
转载请注明出处:http://blog.csdn.net/u014614038/article/details/51507236
根据前面两文,知道了一点是,Fresco获取数据的过程分成了不同的producer进行不同的任务,他们之间通过consumer进行数据传递,这个有的类似与职责链模式,不同的producer有不同的职责,它复杂找缓存、它负责编码、它负责获取网络数据、、等等。我简单画了个图:
这个是简单大概的图,可以概括说明了Fresco获取数据的整个流程思路,事实上会比这个复杂多,如图示,每个producer其实就是复杂一个职责的工作,有些是获取缓存数据,也有些进行编码、进行缓存、进行网络获取等等,一开始请求数据后应该是去缓存获取producer1那里请求数据,有就直接返回不会进行下面的操作,没有缓存获取producer1会交给下一个producer处理,以此类推下去,最终不得已只好去获取网络数据,这期间包含一系列的producer,形成一条职责链,完成了整个获取数据的过程。
我们看看请求数据的入口:
@Override protected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest( ImageRequest imageRequest, Object callerContext, boolean bitmapCacheOnly) { if (bitmapCacheOnly) { return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext); } else { return mImagePipeline.fetchDecodedImage(imageRequest, callerContext); } }
我们略过跳的获取网络数据的那个方法里,具体请看在Fresco源码赏析 之基本流程:
/** * swallow result if prefetch -> bitmap cache get -> wait if scrolling -> * 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; }
这里返回的是一个网络获取的producer,事实上是多个producer的链,这里返回的只是链头而已,最终从链头走到链为,这个过程可能中断也可能完全走完,但是从代码上看的画,这个链肯定是完整 ,newBitmapCacheGetToDecodeSequence返回的是一个producer,它的下个pruducer是getCommonNetworkFetchToEncodedMemorySequence()返回的pruducer,我们具体看看这两个方法:
先看前一个:
/** * Same as {@code newBitmapCacheGetToBitmapCacheSequence} but with an extra DecodeProducer. * @param nextProducer next producer in the sequence after decode * @return bitmap cache get to decode sequence */ private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToDecodeSequence( Producer<CloseableReference<PooledByteBuffer>> nextProducer) { DecodeProducer decodeProducer = mProducerFactory.newDecodeProducer(nextProducer);//这个是对图片数据进行编码,并用一些比较复杂的算法进行扫描处理 return newBitmapCacheGetToBitmapCacheSequence(decodeProducer); }
/** * Bitmap cache get -> wait if scrolling -> thread hand off -> multiplex -> bitmap cache * @param nextProducer next producer in the sequence after bitmap cache * @return bitmap cache get to bitmap cache sequence */ private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToBitmapCacheSequence( Producer<CloseableReference<CloseableImage>> nextProducer) { BitmapMemoryCacheProducer bitmapMemoryCacheProducer = mProducerFactory.newBitmapMemoryCacheProducer(nextProducer);//这个是去bitmap缓存找有没有缓存,并且如果需要缓存的话将数据缓存并复制一份数据,将复制的数据返回 BitmapMemoryCacheKeyMultiplexProducer bitmapKeyMultiplexProducer = mProducerFactory.newBitmapMemoryCacheKeyMultiplexProducer(bitmapMemoryCacheProducer);//这个是合并请求,如何多个请求获取的是同一张图片的画将请求合并成一个,为了只保存一份数据 ThreadHandoffProducer<CloseableReference<CloseableImage>> threadHandoffProducer = mProducerFactory.newBackgroundThreadHandoffProducer(bitmapKeyMultiplexProducer);//这个是启动线程,让接下来的pruducer全都在线程中执行 return mProducerFactory.newBitmapMemoryCacheGetProducer(threadHandoffProducer);//这个是单纯去bitmap缓存找有没有数据 }
看到方法传入的参数没有,nextProducer,就是说传入的producer是下一个职责负责的producer,就是当前producer完成后如果有必要就交给下个producer处理,比如找了发现没有缓存数据,那么就交给图片数据编码的producer处理,它就不管了。同理mProducerFactory传入的参数名也叫nextproducer,就是它创建的那个producer的下一个producer就是传入的那个,这样下来就形成了一个完整的链了。
看后一个方法:
/** * multiplex -> encoded cache -> disk cache -> (webp transcode) -> network fetch. */ private synchronized Producer<CloseableReference<PooledByteBuffer>> getCommonNetworkFetchToEncodedMemorySequence() { if (mCommonNetworkFetchToEncodedMemorySequence == null) { mCommonNetworkFetchToEncodedMemorySequence = newEncodedCacheMultiplexToTranscodeSequence(mNetworkFetchProducer, /* isLocal */false); if (mResizeAndRotateEnabledForNetwork) { mCommonNetworkFetchToEncodedMemorySequence = newResizeAndRotateImagesSequence(mCommonNetworkFetchToEncodedMemorySequence); } } return mCommonNetworkFetchToEncodedMemorySequence; }
其实这个mNetworkFetchProducer才是最后发起网络请求进行数据获取的producer,这样标志一下。
/** * encoded cache multiplex -> encoded cache -> (disk cache) -> (webp transcode) * @param nextProducer next producer in the sequence * @param isLocal whether the image source is local or not * @return encoded cache multiplex to webp transcode sequence */ private Producer<CloseableReference<PooledByteBuffer>> newEncodedCacheMultiplexToTranscodeSequence( Producer<CloseableReference<PooledByteBuffer>> nextProducer, boolean isLocal) { if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) { nextProducer = mProducerFactory.newWebpTranscodeProducer(nextProducer);//将获取到的图片转码 } if (!isLocal) { nextProducer = mProducerFactory.newDiskCacheProducer(nextProducer);//将获取到的数据缓存到硬盘 } EncodedMemoryCacheProducer encodedMemoryCacheProducer = mProducerFactory.newEncodedMemoryCacheProducer(nextProducer);//根据编码后的缓存路径寻找有没有编码后的缓存,有就返回没有就进行下一步 return mProducerFactory.newEncodedCacheKeyMultiplexProducer(encodedMemoryCacheProducer);//根据编码后的缓存的图片请求路径,对于同一个图片路径的不同缓存的不同请求合并成一个 }
根据上面的两个方法,我简单整理了一下整个职责链:
是不是感觉有的怪,事实上有些producer不是在上一个producer传递下来时执行的,它是在数据返回时执行的比如编码、转码之类的,这个实现就是通过consumer实现的,consumer说是传递在整个链里面,实现它在必要的producer中会重新创建一个进行对数据返回时的拦截并进行相应的处理,如缓存producer,没有缓存的时候应该是去获取网络数据,进行这步有什么意义?其实它在这里做的缓存处理只是在consumer数据回调时对数据进行缓存,它的做法就是创建一个新的consumer,将新的consumer传递到下一个producer,最终数据通过这个新的consumer返回回来,它获取到数据后进行缓存处理,处理完通过就的consumer返回回去。我个人觉得这样的设计非常巧妙,让所有的producer衔接起来。
下面是缓存producer在上个producer传递下来执行的操作:
@Override public void produceResults(final Consumer<CloseableReference<T>> consumer, final ProducerContext producerContext) { final ProducerListener listener = producerContext.getListener(); final String requestId = producerContext.getId(); listener.onProducerStart(requestId, getProducerName()); final K cacheKey = getCacheKey(producerContext.getImageRequest()); CloseableReference<T> cachedReference = mMemoryCache.get(cacheKey, null); if (cachedReference != null) {// 不为空说明拿到的内存的缓存数据 boolean shouldStartNextProducer = shouldStartNextProducer(cachedReference); if (!shouldStartNextProducer) {// 是否进行下一个produder操作,不需要就将结果返回当前的producer listener.onProducerFinishWithSuccess(requestId, getProducerName(), listener.requiresExtraMap(requestId) ? ImmutableMap.of(CACHED_VALUE_FOUND, "true") : null); } consumer.onNewResult(cachedReference, !shouldStartNextProducer); cachedReference.close(); if (!shouldStartNextProducer) { return; } } // 当内存缓存没有数据说明内存数据清掉了,进行下个操作 Consumer<CloseableReference<T>> consumerOfNextProducer;// 下一个生存者的消费者,生存者主要是用来进行获取数据的操作,消费者主要是用于处理数据的操作 if (!shouldCacheReturnedValues()) {//如果当前生存者的消费者不需要进行数据处理,就将当前消费者指定为下个生存者的消费者,否则进行数据处理 consumerOfNextProducer = consumer; } else { //必要的时候创建了一个新的consumer传递下去,这样对就可以对数据进行拦截 consumerOfNextProducer = new BaseConsumer<CloseableReference<T>>() { @Override public void onNewResultImpl(CloseableReference<T> newResult, boolean isLast) { CloseableReference<T> cachedResult = null;//newResult这个结果是下面的生存者传递回来的数据,然后将数据返回给前一个消费者 if (newResult != null && shouldCacheResult(newResult, cacheKey, isLast)) { cachedResult = mMemoryCache.cache(cacheKey, newResult); } if (cachedResult != null) {//缓存操作后通过旧的consumer将数据返回回去 consumer.onNewResult(cachedResult, isLast); cachedResult.close(); } else { consumer.onNewResult(newResult, isLast); } } @Override public void onFailureImpl(Throwable t) { consumer.onFailure(t); } @Override protected void onCancellationImpl() { consumer.onCancellation(); } }; } listener.onProducerFinishWithSuccess(requestId, getProducerName(), listener.requiresExtraMap(requestId) ? ImmutableMap.of(CACHED_VALUE_FOUND, "false") : null); mNextProducer.produceResults(consumerOfNextProducer, producerContext);//这里进行跳转到下个生存者 }
所以去实际上本身的职责工作是在数据返回时才进行,其他有些producer也是类似的做法。
好啦,producer的流程大概说明白了,其每个producer具体实现就不说了,毕竟太多了,根据这个思路去看很容易就看明白了。
转载请注明出处:http://blog.csdn.net/u014614038/article/details/51507236
相关文章推荐
- iOS 简单计算文件Cache的大小(项目中用了IASKAppSettingsViewController,一个设置界面的库)
- python 练习 13
- HttpClient方式模拟http请求设置头
- JS代码实现table数据分页效果
- [判断手机网络状态]
- Wonderware配置-Historian保存Intouch采集的数据 7
- 计算机网络知识库
- JavaScript基础
- 抢戏!BAT如何共享万达华谊的影视产业蛋糕?
- Kylin介绍
- leetcode记录 231. Power of Two
- android 插件开发
- ACP和PMP区别在哪儿 联系又在哪儿
- JAVA thread0.interrupt()方法
- Runtime是什么?
- 自学FFmpeg(1)
- 【深入浅出Node.js系列三】深入Node.js的模块机制
- Java过滤器与SpringMVC拦截器之间的关系与区别
- Kafka 0.10.0.+zookeeper3.4.8集群搭建、配置,新Client API介绍
- ASE :Space available in segment 'logsegment' has fallen critically low in database