zoukankan      html  css  js  c++  java
  • Fresco 源码分析(三) Fresco服务端处理(2) Producer具体实现的内容

    我们以mProducerFactory.newNetworkFetchProducer()为例,因为这些创建新的producer的方式类似,区别在于是否有包装的处理器,即如果当前处理器中没有正在处理的数据或者等待处理的数据,便交给包装的处理器来处理

    在查看NetworkFetchProducer的源码之前,先来看看producer的接口

    Producer的源码

    这个接口的功能其实看看类和方法的注释就知道了,就是用于产生结果的,这个使用与网络数据的获取,磁盘缓存,内存缓存,解码,编码和图片的变性处理等等
    这种设计模式的特点的好处在于,将图片整体处理的逻辑打散为不同的区块处理,这样实现了模块化

    /**
     * Building block for image processing in the image pipeline.
     *
     * <p> Execution of image request consists of multiple different tasks such as network fetch,
     * disk caching, memory caching, decoding, applying transformations etc. Producer<T> represents
     * single task whose result is an instance of T. Breaking entire request into sequence of
     * Producers allows us to construct different requests while reusing the same blocks.
     *
     * <p> Producer supports multiple values and streaming.
     *
     * @param <T>
     */
    public interface Producer<T> {
    
      /**
       * Start producing results for given context. Provided consumer is notified whenever progress is
       * made (new value is ready or error occurs).
       * @param consumer
       * @param context
       */
      void produceResults(Consumer<T> consumer, ProducerContext context);
    }
    

    在继续分析Producer的处理逻辑之前,我们先把遗留的Q5问题解决: 即ProducerSequenceFactory.newBitmapCacheGetToDecodeSequence()的源码分析续
    再来回顾一下:

    ProducerSequenceFactory.newBitmapCacheGetToDecodeSequence()的源码
    上篇已经提到了根据网络的请求的producer,然后生成了解码的producer,在根据这个解码的producer,生成newBitmapCacheGetToBitmapCacheSequence

      /**
         * 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<EncodedImage> nextProducer) {
            DecodeProducer decodeProducer = mProducerFactory.newDecodeProducer(nextProducer);
            return newBitmapCacheGetToBitmapCacheSequence(decodeProducer);
        }
    

    那么下面需要关注的就是newBitmapCacheGetToBitmapCacheSequence()的过程

    ** ProducerSequenceFactory.newBitmapCacheGetToBitmapCacheSequence()的源码 **

    这段逻辑其实就是ImagePipeline最先处理逻辑的倒叙,就是从bitmapCacheCacheGetProducer到HandlerOff的处理,BitmapCache的生成的倒叙
    将包装处理类一步步传递给上层处理器

      /**
       * Bitmap cache get -> 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);
        BitmapMemoryCacheKeyMultiplexProducer bitmapKeyMultiplexProducer =
            mProducerFactory.newBitmapMemoryCacheKeyMultiplexProducer(bitmapMemoryCacheProducer);
        ThreadHandoffProducer<CloseableReference<CloseableImage>> threadHandoffProducer =
            mProducerFactory.newBackgroundThreadHandoffProducer(bitmapKeyMultiplexProducer);
        return mProducerFactory.newBitmapMemoryCacheGetProducer(threadHandoffProducer);
      }
    

    由于初始化过程的类似,我们直接跳到这个方法最后的new过程,newBitmapMemoryCacheGetProducer()方法
    直接看这个过程,发现

      public BitmapMemoryCacheGetProducer newBitmapMemoryCacheGetProducer(
          Producer<CloseableReference<CloseableImage>> nextProducer) {
        return new BitmapMemoryCacheGetProducer(mBitmapMemoryCache, mCacheKeyFactory, nextProducer);
      }
    
    
      public BitmapMemoryCacheGetProducer(
          MemoryCache<CacheKey, CloseableImage> memoryCache,
          CacheKeyFactory cacheKeyFactory,
          Producer<CloseableReference<CloseableImage>> nextProducer) {
        super(memoryCache, cacheKeyFactory, nextProducer);
      }
    

    暂且先看到这里,做个标记,由于中间处理的逻辑大体相似,所以我们分析producer的一头一尾即可,知道中间的处理流程,一个是处理的头部BitmapMemoryCacheGetProducer, 另外一个是尾部NetworkFetchProducer,但是如果在深入分析,我们就会陷入细节,先将ImagePipeline的整体分析完后,我们再分析这里,标记为Q6:分析BitmapMemoryCacheGetProducer和NetworkFetchProducer

    4.3.1.2 ImagePipeline.fetchDecodedImage() 源码分支2的处理

    由于中间已经分析了producer的很多知识,所以我们先回顾一下ImagePipeline的fetchDecodedImage()的过程

    ImagePipeline.fetchDecodedImage() 源码
    1.获取到producer
    2.根据生成的producer提交请求

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

    分支1已经在4.3.1.1中分析,接下来分析producer的提交请求

    ImagePipeline.submitFetchRequest()源码

    1. 计算出当前图片请求的最低的请求级别

    2. 创建一个SettableProducerContext

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

    上面的逻辑看起来很简单,包涵的知识挺多的,咱们一个一个说

    1. 计算出当前图片请求的最低的请求级别

    根据前一个方法的调用的参数,得知是与最低级别的ImageRequest.RequestLevel.BITMAP_MEMORY_CACHE,所以在提交请求时最低级别就是我们在请求中设置的级别
    2. 创建一个SettableProducerContext

    ProducerContext也是请求信息的一个上下文,这里包含了所有在producer处理过程中需要得知的信息,例如图片的请求信息,请求的优先级,请求的id,是否要预处理等等.

    1. 根据创建的settableProducerContext,再将利用Producer和DataSource中间的适配器,创建了一个DataSource(需要理解的核心部分),并且做了返回

    过程1和过程2比较简单,这个可以自己看看哈,大概作用就是上面描述的,我们来看看过程3

    CloseableProducerToDataSourceAdapter.create(
    	          producerSequence,
    	          settableProducerContext,
    	          mRequestListener);
    

    创建了一个可关闭的生产者到数据源的适配器,就是讲生产者和数据源进行了关联,这个类似于连接器的一个作用,其实发送请求的核心逻辑位于这个地方,因为Producer只是负责生产数据,需要有对应的Consumer来消费数据,数据源是DataSource,那么消费的数据如何得到这个通知呢?这个其实就是客户端的DataSubscriber(剧透一下),其实数据适配器就是做了这样的一个逻辑.算是剧透了,下面我们开始一步一步分析这个过程

    安卓源码分析群: Android源码分析QQ1群号:164812238

    安卓源码分析群: Android源码分析QQ1群号:164812238

  • 相关阅读:
    macOS 升级后重装命令行工具的问题
    Windows系统制作Ubuntu启动U盘(命令行)
    远程管理相关命令的学习(域名和端口号的概念)
    远程管理相关命令的学习(ssh工作方式的简介)
    远程管理相关命令的学习(网卡和IP地址)
    远程管理相关命令的学习(shutdown)
    其他命令的使用(echo find 硬软链接)
    文件内容相关命令(cat more grep)
    拷贝和移动文件(tree cp mv命令的使用)
    touch mkdir rm命令的使用
  • 原文地址:https://www.cnblogs.com/pandapan/p/4784412.html
Copyright © 2011-2022 走看看