Fresco 源码分析(三) Fresco服务端处理(4) Producer处理体系的总结
来源:互联网 发布:台湾淘宝跟大陆一样吗 编辑:程序博客网 时间:2024/06/05 10:13
NetworkFetchProducer.produceResults() 相关源码
在中间的producer处理过程中都没有自己适合的处理的时候,最终还是会调用到网络获取的produceResults方法,这便是真正的网络数据获取以及处理的producer.
网络数据获取的细节,这个我们便不关注了,这里可以简单的提一点:
在fresco的对比的demo中,我们发现不仅仅可以使用fresco默认的网络数据获取,还可以使用okhttp,那么这里在个人翻看源码时,发现其网络数据获取器在ImagePipelineConfig中是可以设置的,这就是其设计的丰富的可配置化.
我们重点关注数据返回时是如何处理的,这就需要查看网络数据的callback是如何处理返回的数据.
@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); } }); }
从callback中看到,都调用了networkFetchProducer的处理方法,以数据成功处理的方法onResponse为例,我们继续分析
NetworkFetchProducer.onResponse() 相关源码
我们看到,通过对数据流的操作
1. 不断的读取mByteArrayPool和写入pooledOutputStream
2. 计算向pooledOutputStream中写入的进度,并且通知consumer
3. 如果完全写入完成,处理完成的后续操作
private void onResponse( FetchState fetchState, InputStream responseData, int responseContentLength) throws IOException { final PooledByteBufferOutputStream pooledOutputStream; if (responseContentLength > 0) { pooledOutputStream = mPooledByteBufferFactory.newOutputStream(responseContentLength); } else { pooledOutputStream = mPooledByteBufferFactory.newOutputStream(); } final byte[] ioArray = mByteArrayPool.get(READ_SIZE); try { int length; while ((length = responseData.read(ioArray)) >= 0) { if (length > 0) { pooledOutputStream.write(ioArray, 0, length); maybeHandleIntermediateResult(pooledOutputStream, fetchState); float progress = calculateProgress(pooledOutputStream.size(), responseContentLength); fetchState.getConsumer().onProgressUpdate(progress); } } mNetworkFetcher.onFetchCompletion(fetchState, pooledOutputStream.size()); handleFinalResult(pooledOutputStream, fetchState); } finally { mByteArrayPool.release(ioArray); pooledOutputStream.close(); } }
在这段程序中,我们看到需要使用到流的一些操作,这些流我们标记为Q7,后续我们需要专门来说说这个部分
还是先关注我们的重点,在完成流的写入后,查看handleFinalResult()的部分
NetworkFetchProducer.handleFinalResult() 相关源码
private void handleFinalResult( PooledByteBufferOutputStream pooledOutputStream, FetchState fetchState) { Map<String, String> extraMap = getExtraMap(fetchState, pooledOutputStream.size()); fetchState.getListener() .onProducerFinishWithSuccess(fetchState.getId(), PRODUCER_NAME, extraMap); notifyConsumer(pooledOutputStream, true, fetchState.getConsumer()); }
NetworkFetchProducer.notifyConsumer() 相关源码
private void notifyConsumer( PooledByteBufferOutputStream pooledOutputStream, boolean isFinal, Consumer<EncodedImage> consumer) { CloseableReference<PooledByteBuffer> result = CloseableReference.of(pooledOutputStream.toByteBuffer()); EncodedImage encodedImage = null; try { encodedImage = new EncodedImage(result); encodedImage.parseMetaData(); consumer.onNewResult(encodedImage, isFinal); } finally { EncodedImage.closeSafely(encodedImage); CloseableReference.closeSafely(result); } }
以上两部分的源码,得知handleFinalResult做了如下的操作
1. 想fetchState的listener通知了完成
2. 将result封装为EncodedImage,并且解析其metaDta
3. 向外通知消费者有新的结果产生
4. 关闭了相关对象
刚刚我们已经分析了两个内存处理的producer和网络请求的producer,我们来总结一下producer体系整体处理的流程
Producer体系整体处理的逻辑伪代码
Producer.producerResult 本身是否可以处理 --> 可以处理 --> 直接向外通知consumer做相关的回调 --> 不能处理 --> 是否需要做自身相关的consumer回调的逻辑 --> 需要 --> 代理consumer的相关实现(Impl)方法 --> 不需要 ---> 调用下一个producer来producerResult
启发: 对于一些较大的项目以及sdk封装中,对于流程化的一些代码,我们可以参照Fresco的处理方法,采用代理或者包装的方式,在当前中需要处理的逻辑方法,进行拦截处理,类似于SSH中的Spring,面向切面的编程,拦截过后,添加自身的逻辑.
刚刚我们已经将Producer的相关处理逻辑做了说明,下面我们将未被包装的Consumer进行说明
在前面我们提到了AbstractProducerToDataSourceAdapter,Producer到数据源的适配,其实无论中途怎么进行拦截和代理,最终还是要到适配器来向外界通知我们的结果,这里就用到了createConsumer的实现相关内容
AbstractProducerToDataSourceAdapter.createConsumer() 相关代码
private Consumer<T> createConsumer() { return new BaseConsumer<T>() { @Override protected void onNewResultImpl(@Nullable T newResult, boolean isLast) { AbstractProducerToDataSourceAdapter.this.onNewResultImpl(newResult, isLast); } @Override protected void onFailureImpl(Throwable throwable) { AbstractProducerToDataSourceAdapter.this.onFailureImpl(throwable); } @Override protected void onCancellationImpl() { AbstractProducerToDataSourceAdapter.this.onCancellationImpl(); } @Override protected void onProgressUpdateImpl(float progress) { AbstractProducerToDataSourceAdapter.this.setProgress(progress); } }; }
在这里我们看到,这些方法交给了Adapter的相关方法来处理,还是按照成功处理的逻辑onNewResultImpl来继续分析
AbstractProducerToDataSourceAdapter.onNewResultImpl() 分析
protected void onNewResultImpl(@Nullable T result, boolean isLast) { if (super.setResult(result, isLast)) { if (isLast) { mRequestListener.onRequestSuccess( mSettableProducerContext.getImageRequest(), mSettableProducerContext.getId(), mSettableProducerContext.isPrefetch()); } } }
- 调用super.setResult,向外通知结果(我们关心的处理过程)
- 如果是最终的结果,向外通知RequestListener(RequestListener)可以作为数据统计使用
查看super.setResult的源码发现,
AbstractDataSource.setResult() 相关源码
- 设置内部结果,更改相关状态
向外通知结果(重点)
/**
- Subclasses should invoke this method to set the result to {@code value}.
* This method will return {@code true} if the value was successfully set, or
- {@code false} if the data source has already been set, failed or closed.
* If the value was successfully set and {@code isLast} is {@code true}, state of the
- data source will be set to {@link AbstractDataSource.DataSourceStatus#SUCCESS}.
* {@link #closeResult} will be called for the previous result if the new value was
- successfully set, OR for the new result otherwise.
* This will also notify the subscribers if the value was successfully set.
*Do NOT call this method from a synchronized block as it invokes external code of the
- subscribers.
* - @param value the value that was the result of the task.
- @param isLast whether or not the value is last.
- @return true if the value was successfully set.
*/
protected boolean setResult(@Nullable T value, boolean isLast) {
boolean result = setResultInternal(value, isLast);
if (result) {
notifyDataSubscribers();
}
return result;
}
- Subclasses should invoke this method to set the result to {@code value}.
AbstractDataSource.notifyDataSubscribers() 相关源码分析
通知所有的数据的订阅者,数据已经完成请求,然后请求的回调是在注册时请求的线程池中执行的
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); } } private void notifyDataSubscriber( final DataSubscriber<T> dataSubscriber, final Executor executor, final boolean isFailure, final boolean isCancellation) { executor.execute( new Runnable() { @Override public void run() { if (isFailure) { dataSubscriber.onFailure(AbstractDataSource.this); } else if (isCancellation) { dataSubscriber.onCancellation(AbstractDataSource.this); } else { dataSubscriber.onNewResult(AbstractDataSource.this); } } }); }
说道这里,其实服务端的处理逻辑就已经差不多了,下篇我们将DataSource和DataSubscriber的部分结合起来,即分析client端的请求回调部分(http://blog.csdn.net/ieyudeyinji/article/details/48286059)
安卓源码分析群: Android源码分析QQ1群号:164812238
- Fresco 源码分析(三) Fresco服务端处理(4) Producer处理体系的总结
- Fresco 源码分析(三) Fresco服务端处理(2) Producer具体实现的内容
- Fresco 源码分析(三) Fresco服务端处理(2) Producer具体实现的内容
- Fresco 源码分析(三) Fresco服务端处理(3) DataSource到Producer的适配器逻辑以及BitmapMemoryCacheProducer处理的逻辑
- Fresco 源码分析(三) Fresco服务端处理(1) ImagePipeline为何物
- Fresco 源码分析(四) 后台数据返回到前台的处理 - Drawable体系的介绍(1)
- Fresco 源码分析(四) 后台数据返回到前台的处理 - Drawable体系的介绍(2)
- Fresco之Producer和DataSource之间适配器处理的逻辑
- Fresco 源码分析(四) 后台数据返回到前台的处理 - Drawable体系的介绍(3) 遗留任务预览
- Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题
- Fresco 源码分析(二) Fresco客户端与服务端交互(2) Fresco.initializeDrawee()分析 续
- Fresco之服务器的处理
- Fresco 源码分析(四) 后台数据返回到前台的处理
- Fresco 源码分析(序)
- 源码分析之Fresco
- Fresco源码分析
- Fresco源码分析
- 图片处理篇--Fresco
- 英文论文中“such as, for example, e.g., i.e., etc., et al. ”的用法分析
- Android 可拖动进度条:SeekBar之自定义进度条
- 根文件系统的挂载过程 http://blog.sina.com.cn/s/blog_67e2ef6a0100s8kf.html
- tools:context=".MainActivity的作用
- RecyclerView+ImageLoader打造多选图库
- Fresco 源码分析(三) Fresco服务端处理(4) Producer处理体系的总结
- C++ 虚函数表解析
- Eclilpse导入maven项目,无法自动构建为java项目的问题
- C#中DllImport用法汇总
- addChildViewController等方法
- 打开MyEclipse10是时候提示:Could not create the view: An unexpected exception was thrown.
- ABAP ALV里日期类型的F4帮助
- 【哥德巴赫猜想】LightOJ Goldbach`s Conjecture 1259
- 【iOS程序启动与运转】- RunLoop转载