Fresco正传(5):请求产生和发出请求

前言

请求产生和请求发出的内容,还是很复杂的,这里需要了解一些背景知识。

首先是ImagePipeline的介绍,其实不用我说,在官网上已经给出了基本的介绍:ImagePipeline介绍

其次是Producer模式,在Fresco中请求产生这块,用到了大量的这种概念,将网络数据的获取,磁盘缓存获取,内存缓存获取,解码,编码和图片的变换等等的处理,分为模块处理,并以倒叙的方式联合再一起调用。显得格外的高大上,就是初次见有点难以理解。

public interface Producer<T> {
    void produceResults(Consumer<T> consumer, ProducerContext context);
}

Producer作为一个行为,表示的是生产结果。有了结果就要处理,而produceResults()方法就代表处理结果,那么是谁处理结果我们不知道,所以就由参数传入,故而就有了消费者Consumer

Producer的处理模式在Fresco中表现的也比较奇特,由于网络数据的获取,磁盘缓存获取,内存缓存获取,解码,编码和图片等这些操作是一个流程处理,那么如何将流程性的东西和Producer结合起来呢?

为了成为一个链式,会有如下的代码模式:

public class XXProducer implements Producer {
  private final Producer mInputProducer;

  public XXProducer (Producer inputProducer) {
    mInputProducer = inputProducer;
  }

  @Override
  public void produceResults(Consumer consumer, ProducerContext context) {
    mInputProducer.produceResults(consumer, context);
  }
}

接收一个外部的生产者,并在自身处理结果方法的最后调用外部生产者处理结果的方法。

这样看似先创建外部的生产者,但是实际上最后才调用外部的生产者。所以Fresco实例的创建和反向调用就好像这个样子:

明白了这一点,就开始正式的分析吧。

正文

先回顾下前文,分析到了PipelineDraweeControllerBuilder.getDataSourceForRequest()方法。

@Override
protected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest(
        ImageRequest imageRequest,
        Object callerContext,
        boolean bitmapCacheOnly) {


    if (bitmapCacheOnly /*false*/) {
        return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext);
    } else {
        // 抓取图片
        return mImagePipeline.fetchDecodedImage(imageRequest, callerContext);
    }
}

由于bitmapCacheOnly为false,所以调用的是fetchDecodeImage()方法,而本片文章分析的重点就在这个方法了。

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

产生请求

看一下这句代码:

Producer<CloseableReference<CloseableImage>> producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);

大概的意思是,获取用于图片解码的生产者序列。注意是序列,这说明该操作内部有很多的操作单元。而这其中又分为两种,一个是基础的请求序列,另一个是后处理器。

public Producer<CloseableReference<CloseableImage>> getDecodedImageProducerSequence(
        ImageRequest imageRequest) {

    // 获取基础解码序列请求
    Producer<CloseableReference<CloseableImage>> pipelineSequence = getBasicDecodedImageSequence(imageRequest);

    // 后处理器处理
    if (imageRequest.getPostprocessor() != null) {
        return getPostprocessorSequence(pipelineSequence);
    } else {
        return pipelineSequence;
    }
}

我们关注的重点自然是基础请求序列,后处理器后续有机会再说。继续跟到getBasicDecodedImageSequence()中。

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)) {
         ......
         .....
         省略N多代码
        }
}

此处分支判断的根据是Uri的类型。网络请求的序列最为复杂,这里分析该分支。

private synchronized Producer<CloseableReference<CloseableImage>> getNetworkFetchSequence() {
   if (mNetworkFetchSequence == null) {
       mNetworkFetchSequence =
               // 2,内存缓存解码序列
               newBitmapCacheGetToDecodeSequence(
                       // 1,网络抓取,并解码到内存序列
                       getCommonNetworkFetchToEncodedMemorySequence());
   }
   return mNetworkFetchSequence;
}

还记得在前言中分析的Produer模式的工作原理吗?这里先创建的网络请求编码序列,并将其传入到内存缓存编码序列中去,也就是说最后的时候才会调用网络请求编码序列。

这里简单看一下getCommonNetFetchToEncodedMemorySequence()方法,其中做了:

  1. 创建一个网络请求的生产者
  2. 传递给内存编码的生产者
  3. 如果允许重设大小和旋转,再传递给用于处理旋转和重设大小的生产者。
/**
 * 通用的网络到编码内存的图片获取方式
 * multiplex -> encoded cache -> disk cache -> (webp transcode) -> network fetch.
 */
private synchronized Producer<EncodedImage> getCommonNetworkFetchToEncodedMemorySequence() {
    if (mCommonNetworkFetchToEncodedMemorySequence == null) {

        Producer<EncodedImage> inputProducer = newEncodedCacheMultiplexToTranscodeSequence(
                // 先生成一个网络获取的producer
                mProducerFactory.newNetworkFetchProducer(mNetworkFetcher));

        // 传递给内存编码的producer
        mCommonNetworkFetchToEncodedMemorySequence = ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer);

        if (mResizeAndRotateEnabledForNetwork && !mDownsampleEnabled) {

            // 如果允许网络图片的重新设置大小和旋转,再传递给用于处理旋转和重新设置大小的producer
            mCommonNetworkFetchToEncodedMemorySequence = mProducerFactory.newResizeAndRotateProducer(mCommonNetworkFetchToEncodedMemorySequence);
        }
    }
    return mCommonNetworkFetchToEncodedMemorySequence;
}

经过newNetworkFetchProducer()方法,跟踪到NetworkFetcherProducer类中,类中的producerResults()方法如下。

@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);
             }
         });
}

在这里处理请求结果的回调。在NetworkFetchProducer类的onResponse()方法中,也是进行一系列的流读取操作。这个类就暂时分析到这里。

再回到getNetworkFetchSequence()方法,进入到newBitmapCacheGetToDecodeSequence()方法中。

private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToDecodeSequence(
        Producer<EncodedImage> inputProducer) {
    DecodeProducer decodeProducer = mProducerFactory.newDecodeProducer(inputProducer);
    // 将生产者作为参数传递给下一个生产者
    return newBitmapCacheGetToBitmapCacheSequence(decodeProducer);
}

依旧是创建生产者,传递生产者。继续跟到newBitmapCacheGetToBitmapCacheSequence()方法中。

private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToBitmapCacheSequence(
        Producer<CloseableReference<CloseableImage>> inputProducer) {

    BitmapMemoryCacheProducer bitmapMemoryCacheProducer = mProducerFactory.newBitmapMemoryCacheProducer(inputProducer);
    BitmapMemoryCacheKeyMultiplexProducer bitmapKeyMultiplexProducer = mProducerFactory.newBitmapMemoryCacheKeyMultiplexProducer(bitmapMemoryCacheProducer);
    ThreadHandoffProducer<CloseableReference<CloseableImage>> threadHandoffProducer = mProducerFactory.newBackgroundThreadHandoffProducer(bitmapKeyMultiplexProducer);

    // 内存缓存请求生产者
    return mProducerFactory.newBitmapMemoryCacheGetProducer(threadHandoffProducer);
}

在ImagePipeline介绍中,我们了解到任何一个请求都是先从内存缓存开始的。那么,此处就应该是最内存的生产者。

public class BitmapMemoryCacheGetProducer extends BitmapMemoryCacheProducer {

  @VisibleForTesting static final String PRODUCER_NAME = "BitmapMemoryCacheGetProducer";

  public BitmapMemoryCacheGetProducer(
      MemoryCache<CacheKey, CloseableImage> memoryCache,
      CacheKeyFactory cacheKeyFactory,
      Producer<CloseableReference<CloseableImage>> inputProducer) {
    super(memoryCache, cacheKeyFactory, inputProducer);
  }

  @Override
  protected Consumer<CloseableReference<CloseableImage>> wrapConsumer(
      final Consumer<CloseableReference<CloseableImage>> consumer,
      final CacheKey cacheKey) {
    // since this cache is read-only, we can pass our consumer directly to the next producer
    return consumer;
  }

  @Override
  protected String getProducerName() {
    return PRODUCER_NAME;
  }
}

进入到该类后,发现并没有什么实质性的内容,我们跟到父类中。在produceResults()方法,发现了很多逻辑,其中在最后一句调用下一个生产者的produceResults()方法。其中还用到了代理设计模式:

// 在这里用到了代理设计模式,因为呢,每个producer都会调用consumer的方法,但是不同的producer需要在原有consumer
// 的基础上处理自己的一些逻辑,这里呢?就需要将原来的consumer进行代理,调用时,先处理自己的逻辑,然后调用原有consumer的相关方法即可
Consumer<CloseableReference<CloseableImage>> wrappedConsumer = wrapConsumer(consumer, cacheKey);
listener.onProducerFinishWithSuccess(
        requestId,
        getProducerName(),
        listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
mInputProducer.produceResults(wrappedConsumer, producerContext);

有了下一步调用的produceResults()方法,那么哪里才是第一次调用produceResults()的地方呢? 这个地方肯定就是这一系列请求最先开始的地方。

带着这样的疑问我们进入下一个问题,如何发出请求的。

发送请求

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

不用我说多,submitFetchRequest()方法就是发送请求的地方,跟进去看看做了什么:

  1. 计算出当前图片最低的请求级别
  2. 获得请求信息的上下文
  3. 根据创建的SettableProducerContext,再利用Producer和DataSource的适配器,创建一个DataSource。
private <T> DataSource<CloseableReference<T>> submitFetchRequest(
        Producer<CloseableReference<T>> producerSequence,
        ImageRequest imageRequest,
        ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit,
        Object callerContext) {
    try {
        // 计算出当前当前图片的最低的请求级别
        // 根据前一个方法的调用的参数,得知是与最低级别的ImageRequest.RequestLevel.BITMAP_MEMORY_CACHE,所以在提交请求时最低级别就是我们在请求中设置的级别
        ImageRequest.RequestLevel lowestPermittedRequestLevel =
                ImageRequest.RequestLevel.getMax(
                        imageRequest.getLowestPermittedRequestLevel(),
                        lowestPermittedRequestLevelOnSubmit);

        // ProducerContext也是请求信息的一个上下文,这里包含了所有在producer处理过程中需要得知的信息,例如图片的请求信息,请求的优先级,请求的id,是否要预处理等等.
        SettableProducerContext settableProducerContext = new SettableProducerContext(
                imageRequest,
                generateUniqueFutureId(),
                mRequestListener,
                callerContext,
                lowestPermittedRequestLevel,
    /* isPrefetch */ false,
                imageRequest.getProgressiveRenderingEnabled() ||
                        !UriUtil.isNetworkUri(imageRequest.getSourceUri()),
                imageRequest.getPriority());


        // 根据创建的settableProducerContext,再将利用Producer和DataSource中间的适配器,创建了一个DataSource(需要理解的核心部分)
        return CloseableProducerToDataSourceAdapter.create(
                producerSequence,
                settableProducerContext,
                mRequestListener);
    } catch (Exception exception) {
        return DataSources.immediateFailedDataSource(exception);
    }
}

进入 可关闭的生产者到数据源的适配器CloseableProducerToDataSourceAdapter类中,发现其中没有什么重要的逻辑,提供了几个安全关闭结果的方法。

继续跟踪到父类中,再起构造方法中发现调用了produceResult()

 producer.produceResults(createConsumer(), settableProducerContext);

那么问题来了,这个producer是谁? 其实不用我多说,你们也能猜到,肯定是内存缓存生产者BitmapMemoryCacheProducer类。由这里开始,就一层一层的向外调用包裹的生产者,直到最后的网络请求。

生产者第一次调用的地方被找到了,那么消费结果的消费者也出现了:createConsumer(),在方法内部创建BaseConsumer匿名内部类的实例,并将回调结果传递给AbstractProducerToDataSourceAdapter类内的方法。

当结果产生时会调用onNewResultImple() 方法。

protected void onNewResultImpl(@Nullable T result, boolean isLast) {
   // 向外通知结果
   if (super.setResult(result, isLast)) {
       if (isLast) {
           mRequestListener.onRequestSuccess(
                   mSettableProducerContext.getImageRequest(),
                   mSettableProducerContext.getId(),
                   mSettableProducerContext.isPrefetch());
       }
   }
}

看一下AbstractProducerToDataSourceAdapter类的继承体系你会发现其继承AbstractDataSource,而AbstractDataSource类实现了DataSource接口,代表其也是个被观察者。

观察者在哪里? 被观察者如何将结果通知给观察者呢?

不知道你是否还记得BaseDataSubscriber抽象类呢? 在AbstractDraweeController类的submitRequest()方法中,构建了BaseDataSubscriber()类的的实例,这里用于处理观察者传递出来的结果。

final DataSubscriber<T> dataSubscriber =
      new BaseDataSubscriber<T>() {
          @Override
          public void onNewResultImpl(DataSource<T> dataSource) {
              // isFinished must be obtained before image, otherwise we might set intermediate result
              // as final image.
              boolean isFinished = dataSource.isFinished();
              float progress = dataSource.getProgress();
              T image = dataSource.getResult();
              if (image != null) {
                  onNewResultInternal(id, dataSource, image, progress, isFinished, wasImmediate);
              } else if (isFinished) {
                  onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true);
              }
          }

          @Override
          public void onFailureImpl(DataSource<T> dataSource) {
              onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true);
          }

          @Override
          public void onProgressUpdate(DataSource<T> dataSource) {
              boolean isFinished = dataSource.isFinished();
              float progress = dataSource.getProgress();
              onProgressUpdateInternal(id, dataSource, progress, isFinished);
          }
      };

找到了观察者,那么如何被观察者如何将结果通知给观察者呢?

回到被观察者AbstractProducerToDataSourceAdapter类的onNewResultImple()方法,其中发现调用了如下代码,将获得的结果通知给外部:


super.setResult(result, isLast);

跟踪到父类中看看,在方法内部调用了notifyDataSubscribers()方法,通知所有的观察者:

protected boolean setResult(@Nullable T value, boolean isLast) {
  boolean result = setResultInternal(value, isLast);
  if (result) {
    notifyDataSubscribers();
  }
  return result;
}
 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);
   }
 }

这样,整个Fresco请求的产生和消费,以及如何将结果传递给外部并相应的流程就打通了。下面再给一张图,哈哈。

最后

欢迎多多拍砖

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值