Fresco 源码分析(三) Fresco服务端处理(4) Producer处理体系的总结

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());
          }
        }
      }
  1. 调用super.setResult,向外通知结果(我们关心的处理过程)
  2. 如果是最终的结果,向外通知RequestListener(RequestListener)可以作为数据统计使用

查看super.setResult的源码发现,

AbstractDataSource.setResult() 相关源码

  1. 设置内部结果,更改相关状态
  2. 向外通知结果(重点)

    /**

    • 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;
      }

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI老潘信息差

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值