Fresco源码赏析 之 基本流程

来源:互联网 发布:centos识别u盘 编辑:程序博客网 时间:2024/04/30 13:21

转载请注明出处:http://blog.csdn.net/u014614038/article/details/51480072


关于 Fresco

Fresco 是一个强大的图片加载组件。

Fresco 中设计有一个叫做 image pipeline 的模块。它负责从网络,从本地文件系统,本地资源加载图片。为了最大限度节省空间和CPU时间,它含有3级缓存设计(2级内存,1级文件)。

Fresco 中设计有一个叫做 Drawees 模块,方便地显示loading图,当图片不再显示在屏幕上时,及时地释放内存和空间占用。

Fresco 支持 Android2.3(API level 9) 及其以上系统。

这么强大而优秀的开源项目,学习学习人家的源码是非常不错的,看了一两天,记录一下自己的笔记与见解。源码比较复杂,我的看法不一定对,如有错误之处欢迎指出,欢迎交流学习。

fresco作为一个图片加载框架肯定离不开数据或者,数据缓存等基本流程。如下图描述那样。


实际上,通过查看源码,Fresco使用的时候是这样的:提交请求------》获取数据

提交请求很容易理解,难点就是获取数据的过程,它获取数据的过程基本是上图的逆过程进行的,就是提交了请求-----》判断有没有缓存内存--------》没有获取网络数据

下面通过源码去看看整个流程,为了不被细节干扰,我们主要看主干线就行了,这样可以把握整体的逻辑流程。

fresco的简单使用是这样的:

Uri uri = Uri.parse("https://raw.githubusercontent.com/facebook/fresco/gh-pages/static/fresco-logo.png");SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);draweeView.setImageURI(uri);

只传递了图片的url,它会自动帮你把所有事情做了,找到这个draweeView.setImageURI(uri);

  /**   * Displays an image given by the uri.   *   * @param uri uri of the image   * @undeprecate   */  @Override  public void setImageURI(Uri uri) {    setImageURI(uri, null);  }  /**   * Displays an image given by the uri.   *   * @param uri uri of the image   * @param callerContext caller context   */  public void setImageURI(Uri uri, @Nullable Object callerContext) {  //controller是com.facebook.drawee.backends.pipeline.PipelineDraweeController    DraweeController controller = mSimpleDraweeControllerBuilder        .setCallerContext(callerContext)        .setUri(uri)        .setOldController(getController())        .build();    setController(controller);  }

这里我们必须找到DraweeController controller是哪个,我们看看mSimpleDraweeControllerBuilder是什么。

 private void init() {    Preconditions.checkNotNull(        sDraweeControllerBuilderSupplier,        "SimpleDraweeView was not initialized!");    //可以看到这个初始化的时候初始化了mSimpleDraweeControllerBuilder,是通过sDraweeControllerBuilderSupplier获取的 mSimpleDraweeControllerBuilder = sDraweeControllerBuilderSupplier.get();  }


然而在初始化的时候初始化了这个sDraweeControllerBuilderSupplier

/** Initializes {@link SimpleDraweeView} with supplier of Drawee controller builders. */  public static void initialize(      Supplier<? extends SimpleDraweeControllerBuilder> draweeControllerBuilderSupplier) {    sDraweeControllerBuilderSupplier = draweeControllerBuilderSupplier;  }

而这个方法是在Fresco这个类的的初始化方法了被执行的,就是说fresco在初始化的时候就初始化了这个相关配置。

/** Initializes Fresco with the default config. */  public static void initialize(Context context) {    ImagePipelineFactory.initialize(context);    initializeDrawee(context);  }  /** Initializes Fresco with the specified config. */  public static void initialize(Context context, ImagePipelineConfig imagePipelineConfig) {    ImagePipelineFactory.initialize(imagePipelineConfig);    initializeDrawee(context);  }  private static void initializeDrawee(Context context) {    sDraweeControllerBuilderSupplier = new PipelineDraweeControllerBuilderSupplier(context);   SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);      }


同时 我们知道了mSimpleDraweeControllerBuilder 就是PipelineDraweeControllerBuilderSupplier的get(),返回的,看看这个get的方法:


 @Override  public PipelineDraweeControllerBuilder get() {    return newPipelineDraweeControllerBuilder(        mContext,        mPipelineDraweeControllerFactory,        mImagePipeline,        mBoundControllerListeners);  }


看看这个builder的build的方法返回的是什么:


/** Builds the specified controller. */@Overridepublic AbstractDraweeController build() {validate();// if only a low-res request is specified, treat it as a final request.if (mImageRequest == null && mMultiImageRequests == null && mLowResImageRequest != null) {mImageRequest = mLowResImageRequest;mLowResImageRequest = null;}return buildController();}



/** Builds a regular controller. */protected AbstractDraweeController buildController() {AbstractDraweeController controller = obtainController();maybeBuildAndSetRetryManager(controller);maybeAttachListeners(controller);return controller;}



 @Override  protected PipelineDraweeController obtainController() {    DraweeController oldController = getOldController();    PipelineDraweeController controller;    if (oldController instanceof PipelineDraweeController) {      controller = (PipelineDraweeController) oldController;      controller.initialize(          obtainDataSourceSupplier(),          generateUniqueControllerId(),          getCallerContext());    } else {     mPipelineDraweeControllerFactory.newController(          obtainDataSourceSupplier(),          generateUniqueControllerId(),          getCallerContext());    }    return controller;  }

可以看到它通过工厂模式去生成controller:

 public PipelineDraweeController newController(      Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,      String id,      Object callerContext) {    return new PipelineDraweeController</span>(        mResources,        mDeferredReleaser,        mAnimatedDrawableFactory,        mUiThreadExecutor,        dataSourceSupplier,        id,        callerContext);  }


走了那么远,终于可以回去,回到原点看。

 /**   * Displays an image given by the uri.   *   * @param uri uri of the image   * @param callerContext caller context   */  public void setImageURI(Uri uri, @Nullable Object callerContext) {  //controller是com.facebook.drawee.backends.pipeline.PipelineDraweeController    DraweeController controller</span> = mSimpleDraweeControllerBuilder        .setCallerContext(callerContext)        .setUri(uri)        .setOldController(getController())        .build();    setController(controller);  }


现在我们知道了一点:这个SimpleDraweeView 使用的控制器是PipelineDraweeController;

现在问题是setController(controller);后发生了什么,为什么用了这个方法后所有处理都自动完成了呢。

我们看看这个setController(controller);方法:

 /** Sets the controller. */  public void setController(@Nullable DraweeController draweeController) {    mDraweeHolder.setController(draweeController);    super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());  }


这里将控制器传进了holder里面。这里简单说一下,fresco采用的是典型的mvc模式,DraweeHierarchy 负责的是跟显示相关的,DraweeController 负责的是后台相关的,DraweeHolder主要是统筹两者的,其他还有一下事件记录等。官方是这么说的:

A holder class for Drawee controller and hierarchy.

返回到上面看这个setController方法:


 /*
   * Sets a new controller.   */  public void setController(@Nullable DraweeController draweeController) {    boolean wasAttached = mIsControllerAttached;    if (wasAttached) {      detatchController();    }   .....    if (wasAttached) {      <span style="color: rgb(255, 0, 0);">attachController();</span>    }  }


 private void attachController() {    if (mIsControllerAttached) {      return;    }    mEventTracker.recordEvent(Event.ON_ATTACH_CONTROLLER);    mIsControllerAttached = true;    if (mController != null &&        mController.getHierarchy() != null) {      mController.onAttach();    }  }



看到了么,它调用了controller的onAttach()方法,我们已经知道了这个controller是PipelineDraweeController,我们去看看这个方法:


  @Override  public void onAttach() {    if (FLog.isLoggable(FLog.VERBOSE)) {      FLog.v(          TAG,          "controller %x %s: onAttach: %s",          System.identityHashCode(this),          mId,          mIsRequestSubmitted ? "request already submitted" : "request needs submit");    }    mEventTracker.recordEvent(Event.ON_ATTACH_CONTROLLER);    Preconditions.checkNotNull(mSettableDraweeHierarchy);    mDeferredReleaser.cancelDeferredRelease(this);    mIsAttached = true;    if (!mIsRequestSubmitted) {    submitRequest();//看到没这里进行了提交请求    }  }


我们看看这个提交的方法:

 protected void submitRequest() {    mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT);    getControllerListener().onSubmit(mId, mCallerContext);    mSettableDraweeHierarchy.setProgress(0, true);    mIsRequestSubmitted = true;    mHasFetchFailed = false;   mDataSource = getDataSource();//获取数据    if (FLog.isLoggable(FLog.VERBOSE)) {      FLog.v(          TAG,          "controller %x %s: submitRequest: dataSource: %x",          System.identityHashCode(this),          mId,          System.identityHashCode(mDataSource));    }    final String id = mId;    final boolean wasImmediate = mDataSource.hasResult();    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();            T image = dataSource.getResult();            if (image != null) {              onNewResultInternal(id, dataSource, image, 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);          }        };            mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor);//这个将获取的数据回调到ui线程</span>  }

可以看到,这里大概可以知道了,获取到数据,然后将数据提交到ui线程去,那么我们这里关心的有两个,1.如何获取到数据。 2.提交数据后怎么处理。

我们分开去看比较好,这里将获取后数据处理标志为Q1,先不管这个,我们先重点关心它是怎么获取到数据的。

然后获取到数据,那么 我们看这个方法mDataSource = getDataSource();//获取数据,这里发现是一个抽象方法,找到其实现:

 @Override  protected DataSource<CloseableReference<CloseableImage>> getDataSource() {    if (FLog.isLoggable(FLog.VERBOSE)) {      FLog.v(TAG, "controller %x: getDataSource", System.identityHashCode(this));    }    return mDataSourceSupplier.get();  }


这里出现了一个mDataSourceSupplier,发现这个mDataSourceSupplier只有在两个地方传递进去,一个是构造器,还有一个是initialize方法,而这个方法只有在PipelineDraweeControllerBuilder的obtainController()时调用到:


 @Ove<span style="font-family: Arial, Helvetica, sans-serif;">rride</span>
  protected PipelineDraweeController obtainController() {    DraweeController oldController = getOldController();    PipelineDraweeController controller;    if (oldController instanceof PipelineDraweeController) {      controller = (PipelineDraweeController) oldController;      controller.initialize(          obtainDataSourceSupplier(),          generateUniqueControllerId(),          getCallerContext());    } else {      controller = mPipelineDraweeControllerFactory.newController(          obtainDataSourceSupplier(),          generateUniqueControllerId(),          getCallerContext());    }    return controller;  }

可以看到了,在创建那个控制器的时候同时会初始化那个数据提供者Supplier<DataSource<IMAGE>>,我们看看这个东西是怎么创建的:

/** Gets the top-level data source supplier to be used by a controller. */</span>protected Supplier<DataSource<IMAGE>> obtainDataSourceSupplier() {if (mDataSourceSupplier != null) {return mDataSourceSupplier;}Supplier<DataSource<IMAGE>> supplier = null;// final image supplier;if (mImageRequest != null) {supplier = getDataSourceSupplierForRequest(mImageRequest);//根据请求获取数据提供者} else if (mMultiImageRequests != null) {supplier = getFirstAvailableDataSourceSupplier(mMultiImageRequests);}// increasing-quality supplier; highest-quality supplier goes firstif (supplier != null && mLowResImageRequest != null) {List<Supplier<DataSource<IMAGE>>> suppliers = Lists.newArrayListWithCapacity(2);suppliers.add(supplier);suppliers.add(getDataSourceSupplierForRequest(mLowResImageRequest));supplier = IncreasingQualityDataSourceSupplier.create(suppliers);}// no image requests; use null data source supplierif (supplier == null) {supplier = DataSources.getFailedDataSourceSupplier(NO_REQUEST_EXCEPTION);}return supplier;}



/** Creates a data source supplier for the given image request. */protected Supplier<DataSource<IMAGE>> getDataSourceSupplierForRequest(REQUEST imageRequest){return getDataSourceSupplierForRequest(imageRequest, /* bitmapCacheOnly */ false);}
/** Creates a data source supplier for the given image request. */protected Supplier<DataSource<IMAGE>> getDataSourceSupplierForRequest(final REQUEST imageRequest,final boolean bitmapCacheOnly) {final Object callerContext = getCallerContext();return new Supplier<DataSource<IMAGE>>() {<span style="color: rgb(255, 0, 0);">//创建一个新的数据提供者</span>@Overridepublic DataSource<IMAGE> get() {return getDataSourceForRequest(imageRequest, callerContext, bitmapCacheOnly);//获取数据封装到数据提供者}@Overridepublic String toString() {return Objects.toStringHelper(this).add("request", imageRequest.toString()).toString();}};}


看到没有,非常清晰了,这里创建了一个新的数据提供者,而正在获取数据的是getDataSourceForRequest这个方法,这个是抽象方法,很容易找到其实现:

  @Override  protected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest(      ImageRequest imageRequest,      Object callerContext,      boolean bitmapCacheOnly) {    if (bitmapCacheOnly) {      return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext);<span style="color: rgb(255, 0, 0);">//这里获取的是缓存的数据</span>    } else {      return mImagePipeline.fetchDecodedImage(imageRequest, callerContext);//这里获取的解码的imge数据,我们关心的是这个    }  }

千呼万唤始出来啊,看到了,是通过这里mImagePipeline.fetchDecodedImage获取到数据的,我们关心的是它是如何获取网络数据并返回回来了,下面的才是重头戏,至少是我认为精妙之处。好,接着看。mImagePipeline的作用是提交请求将数据返回回来,这里的这个的初始化是在构造器里进行,这个只有在一个地方调用到,就是在PipelineDraweeControllerBuilderSupplier的get方法:

 @Override  public PipelineDraweeControllerBuilder get() {    return new PipelineDraweeControllerBuilder(        mContext,        mPipelineDraweeControllerFactory,        mImagePipeline,        mBoundControllerListeners);  }

咦,熟悉吧这个方法,就是SimpleDraweeView初始化的时候进行的。

 private void init() {    Preconditions.checkNotNull(        sDraweeControllerBuilderSupplier,        "SimpleDraweeView was not initialized!");    //可以看到这个初始化的时候初始化了mSimpleDraweeControllerBuilder,是通过sDraweeControllerBuilderSupplier获取的    mSimpleDraweeControllerBuilder = sDraweeControllerBuilderSupplier.get();  }

哈哈,这样一来都打通了。

我们明白了 mImagePipeline是怎么来后,核心是关注mImagePipeline.fetchDecodedImage(imageRequest, callerContext);这个方法是怎么将数据返回回来的,核心啊!!

/**   * Submits a request for execution and returns a DataSource representing the pending decoded   * image(s).   *   * 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) {    //Returns a sequence that can be used for a request for a decoded image    Producer<CloseableReference<CloseableImage>> producerSequence =        mProducerSequenceFactory.getDecodedImageProducerSequence(            imageRequest);//Q2        return submitFetchRequest(producerSequence, imageRequest, callerContext);  }


这里有两个方法,一个是返回了一个序列,暂时不明白做什么的,一个submitFetchRequest很容易明白,这个方法是返回数据的,我们将前面一个标志为Q2,等下再看,我们先看看这个submitFetchRequest是如何返回数据的:


<span style="font-family: Arial, Helvetica, sans-serif;"> private <T> DataSource<CloseableReference<T>> submitFetchRequest(</span>
      Producer<CloseableReference<T>> producerSequence,      ImageRequest imageRequest,      Object callerContext) {    SettableProducerContext settableProducerContext = new SettableProducerContext(        imageRequest,        generateUniqueFutureId(),        mRequestListener,        callerContext,        /* isPrefetch */ false,        imageRequest.getProgressiveRenderingEnabled() ||            !UriUtil.isNetworkUri(imageRequest.getSourceUri()),        Priority.HIGH);        return CloseableProducerToDataSourceAdapter.create(        producerSequence,        settableProducerContext,        mRequestListener);  }


这里有个SettableProducerContext,看了下注释,大概是提供上下文一样的东西,方便取消请求,先不管。


/** * ProducerContext that allows the client to cancel an image request in-flight. */@ThreadSafepublic class SettableProducerContext implements ProducerContext 


那么核心就是这个方法了:


 return CloseableProducerToDataSourceAdapter.create(        producerSequence,        settableProducerContext,        mRequestListener);

这里传递进去了一个刚才标志为Q2的序列,一个上下文,一个请求监听,看看这个方法源码:


/** * DataSource<CloseableReference<T>> backed by a Producer<CloseableReference<T>> * * @param <T> */@ThreadSafepublic class CloseableProducerToDataSourceAdapter<T>    extends AbstractProducerToDataSourceAdapter<CloseableReference<T>> {  public static <T> DataSource<CloseableReference<T>> create(      Producer<CloseableReference<T>> producer,      SettableProducerContext settableProducerContext,      RequestListener listener) {    return new CloseableProducerToDataSourceAdapter<T>(        producer, settableProducerContext, listener);  }

发现主要核心还是在父类里面:

protected AbstractProducerToDataSourceAdapter(     Producer<T> producer,//这是刚才传递进去的Q2      SettableProducerContext settableProducerContext,      RequestListener requestListener) {    mSettableProducerContext = settableProducerContext;    mRequestListener = requestListener;    mRequestListener.onRequestStart(        settableProducerContext.getImageRequest(),        mSettableProducerContext.getCallerContext(),        mSettableProducerContext.getId(),        mSettableProducerContext.isPrefetch());    //这个createConsumer()是最终返回数据处理的消费者    producer.produceResults(createConsumer(), settableProducerContext);  }
private Consumer<T> createConsumer() {    return new BaseConsumer<T>() {      @Override//新的数据回调</span>      protected void onNewResultImpl(@Nullable T newResult, boolean isLast) {        AbstractProducerToDataSourceAdapter.this.onNewResultImpl(newResult, isLast);      }      @Override//数据获取失败回调</span>      protected void onFailureImpl(Throwable throwable) {        AbstractProducerToDataSourceAdapter.this.onFailureImpl(throwable);      }      @Override//请求取消回调      protected void onCancellationImpl() {        AbstractProducerToDataSourceAdapter.this.onCancellationImpl();      }    };  }  protected void onNewResultImpl(@Nullable T result, boolean isLast) {    if (super.setResult(result, isLast)) {      if (isLast) {        mRequestListener.onRequestSuccess(//是调用            mSettableProducerContext.getImageRequest(),            mSettableProducerContext.getId(),            mSettableProducerContext.isPrefetch());      }    }  }  private void onFailureImpl(Throwable throwable) {    if (super.setFailure(throwable)) {      mRequestListener.onRequestFailure(//mRequestListener将结果返回,成功或者失败          mSettableProducerContext.getImageRequest(),          mSettableProducerContext.getId(),          throwable,          mSettableProducerContext.isPrefetch());    }  }


这里我们发现了,Q2的producer的 producer.produceResults的方法传递进去一个Consumer,然后会自动将数据通过Consumer返回回来,接着通过requestlistener回调回去。这里可以看到了,实现上返回数据回来的还是Q2的那个方法,这里还有个疑问,这个requestlistener是如何将数据返回出去的呢?我们先解决一下这个疑问。

毫无疑问,在这个方法里传进了这个requestlistsner

 return CloseableProducerToDataSourceAdapter.create(        producerSequence,        settableProducerContext,       mRequestListener);


发现这个RequestListsner是ImagePipeline的成员变量,它在构造器就进行初始化:

public ImagePipeline(      ProducerSequenceFactory producerSequenceFactory,      Set<RequestListener> requestListeners,      Supplier<Boolean> isPrefetchEnabledSupplier,      MemoryCache<BitmapMemoryCacheKey, CloseableImage, Void> bitmapMemoryCache,      MemoryCache<CacheKey, PooledByteBuffer, Void> encodedMemoryCache,      CacheKeyFactory cacheKeyFactory) {    mIdCounter = new AtomicLong();    mProducerSequenceFactory = producerSequenceFactory;    mRequestListener = new ForwardingRequestListener(requestListeners);    mIsPrefetchEnabledSupplier = isPrefetchEnabledSupplier;    mBitmapMemoryCache = bitmapMemoryCache;    mEncodedMemoryCache = encodedMemoryCache;    mCacheKeyFactory = cacheKeyFactory;  }


public class ForwardingRequestListener implements RequestListener {  private static final String TAG = "ForwardingRequestListener";  private final List<RequestListener> mRequestListeners;  public ForwardingRequestListener(      Set<RequestListener> requestListeners) {    mRequestListeners = Lists.newArrayListWithCapacity(requestListeners.size());    for (RequestListener requestListener : requestListeners) {      mRequestListeners.add(requestListener);    }  }


通过源码很容易看出来ForwardingRequestListener 维持了一个请求列表,统一管理所有请求监听。ImagePipelineFactory是实行单例模式,这个ImagePipelineFactory是在Fresco初始化时进行初始化的,它也是维持着一个ImagePipeline,就是说通过它一个维持一个请求的监听集合。这里我有点搞不明白,为什么一个image请求所有请求监听都要回调:


  @Override  public void onRequestSuccess(ImageRequest request, String requestId, boolean isPrefetch) {    final int numberOfListeners = mRequestListeners.size();    for (int i = 0; i < numberOfListeners; ++i) {      RequestListener listener = mRequestListeners.get(i);      try {        listener.onRequestSuccess(request, requestId, isPrefetch);      } catch (Exception exception) {        // Don't punish the other listeners if we're given a bad one.        onException("InternalListener exception in onRequestSuccess", exception);      }    }  }

现在可以明白为什么可以通过ImagePipeline获取到数据了吧。

说明那么多基本都通了,还有一点就是Q2问题,它是如何发送请求并获取的数据的呢,这大概是我们最想知道的吧。

我们看Q2 那个方法:


  //Returns a sequence that can be used for a request for a decoded image    Producer<CloseableReference<CloseableImage>> producerSequence =        mProducerSequenceFactory.getDecodedImageProducerSequence(            imageRequest);//Q2

/**   * Returns a sequence that can be used for a request for a decoded image.   *   * @param imageRequest the request that will be submitted   * @return the sequence that should be used to process the request   */  public Producer<CloseableReference<CloseableImage>> getDecodedImageProducerSequence(      ImageRequest imageRequest) {    Producer<CloseableReference<CloseableImage>> pipelineSequence =        getBasicDecodedImageSequence(imageRequest);    if (imageRequest.getPostprocessor() != null) {      return getPostprocessorSequence(pipelineSequence);//这是上个进程的数据    } else {      return pipelineSequence;    }  }

private Producer<CloseableReference<CloseableImage>> getBasicDecodedImageSequence(      ImageRequest imageRequest) {   ...    Uri uri = imageRequest.getSourceUri();    if (UriUtil.isNetworkUri(uri)) {      return getNetworkFetchSequence();    } else if (UriUtil.isLocalFileUri(uri)) {      if (MediaUtils.isVideo(MediaUtils.extractMime(uri.getPath()))) {        return getLocalVideoFileFetchSequence();      } else {        return getLocalImageFileFetchSequence();      }    } else if (UriUtil.isLocalContentUri(uri)) {      return getLocalContentUriFetchSequence();    } else if (UriUtil.isLocalAssetUri(uri)) {      return getLocalAssetFetchSequence();    } else if (UriUtil.isLocalResourceUri(uri)) {      return getLocalResourceFetchSequence();    } else {      throw new RuntimeException(          "Unsupported image type! Uri is: " + uri.toString().substring(0, 30));    }  }



看到了么,这个可以获取很多的数据网络的、本地的、、我们关心的是获取网络数据,就是getNetworkFetchSequence()这个方法:


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


重点来了,我们知道我们请求并获取数据的过程是逆向的,就是提交请求-----判断有没有缓存-------没有缓存网络获取-----获取成功返回。Fresco巧妙的用了两个东西,producer和consumer,我们看官方解析:


/** * 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>

每个image请求都有不同了流程任务,比如网络获取过程、硬盘缓存过程、内存缓存过程、编码过程、传输过程等,每个过程都通过一个producer标识,根据流程每完成一个producer任务就传递给下一个producer执行相应的任务,这样好处很明显,很清晰。执行任务通过producer进行,那么之间的数据传递怎么办,那就是consumer了。


/** * Consumes data produced by {@link Producer}.<T> * * <p> The producer uses this interface to notify its client when new data is ready or an error * occurs. Execution of the image request is structured as a sequence of Producers. Each one * consumes data produced by producer preceding it in the sequence. * * <p>For example decode is a producer that consumes data produced by the disk cache get producer. * * <p> The consumer is passed new intermediate results via onNewResult(isLast = false) method. Each * consumer should expect that one of the following methods will be called exactly once, as the very * last producer call: * <ul> *   <li> onNewResult(isLast = true) if producer finishes successfully with a final result </li> *   <li> onFailure if producer failed to produce a final result </li> *   <li> onCancellation if producer was cancelled before a final result could be created </li> * </ul> * * <p> Implementations of this interface must be thread safe, as callback methods might be called * on different threads. * * @param <T> */public interface Consumer<T>

producer通过consumer将结果返回给client。

那么我们大概就可以猜测了它的流程类似就是producer1-----》producer12--------》producer3--------》producer4,它们之间传递consumer进行数据传递,按照这样的思路看看源码对不对。

前面我们看到了getNetworkFetchSequence()这个方法,这个方法就是获取网络数据的,

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

private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToDecodeSequence(      Producer<CloseableReference<PooledByteBuffer>><span style="color: rgb(255, 0, 0);"> nextProducer</span>) {    DecodeProducer decodeProducer = mProducerFactory.newDecodeProducer(nextProducer);    return newBitmapCacheGetToBitmapCacheSequence(decodeProducer);  }


看到那个传递参数命名没有,叫nextproducer,而且 mProducerFactory.newDecodeProducer这个方法的作用就是创建了一个编码producer,getCommonNetworkFetchToEncodedMemorySequence()这个方法从名字来看就是获取网络数据后进行编码缓存的producer,所以这个方法 mProducerFactory.newDecodeProducer(nextProducer);可以理解为:解码的下一个步骤就是行进行网络或者并编码,同理newBitmapCacheGetToBitmapCacheSequence(decodeProducer)可以理解为:缓存bitmapcache下一个步骤就是进行解码。好像怪怪的,不过想想拿数据的大概就明白了,拿数据时是应该去缓存找,如果找到缓存就直接返回数据,如果没有缓存就进行下一步拿数据。所以上一个producer拿数据成功后就应该不会执行下一个producer,不成功就执行下一个produce去拿数据以此类推下去,应该是这样才对。

我们看下一个方法:


/**   * Bitmap cache get <pre name="code" class="java">/**   * 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;  }

这里的流程可以总结为:获取bitmap memory cache-------》启动ExecutorService进行后台处理-------》同一key多路请求合并成一个--------》获取解码了的bitmap memory cache

我们返回看getCommonNetworkFetchToEncodedMemorySequence():

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


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

其实最最简单的概括就是本文最上面的那张图了,事实上它又不止那么简单,这个详细说明也蛮多的,这里我只说个大概的思路,应该是没错的。那么还有它如何通过consumer进行数据传递,这也是蛮有意思,我想再下次具体详细看这个部分。


简单总结一下这个流程,Fresco是如何只使用setImageURI()后自动完成了获取数据的:

DraweeView采用的 是典型的mvc模式,DraweeHierarchy 负责的是跟显示相关的,DraweeController 负责的是后台相关的,DraweeHolder主要是统筹两者的,Fresco的初始化方法执行后会初始化相关配置。以SimpleDraweeView为例,它的controller是PipelineDraweeController,Fresco在初始化时初始化一个PipelineDraweeControllerBuilderSupplier来提供这个controller,DraweeHolder主要通过controller启动后台服务获取数据,setController方法执行后后调用controller的onAttach()方法,这个方法会提交请求并获得数据,后将数据返回给ui线程,Fresco数据是封装成Supplier<DataSource<IMAGE>> 的形式返回,而真正将数据传递回来的是通过ImagePipeline,这个ImagePipeline会在PipelineDraweeControllerBuilderSupplier的构造器初始化创建一个,它会在Fresco初始化方法中进行初始化,SimpleDraweeView初始化方法中会调用PipelineDraweeControllerBuilderSupplier的get的方法将ImagePipeline返回,ImagePipeline有一个RequestListsner的成员变量,它管理这个一个监听列表,请求监听通过这个RequestListsner返回,而正确去获取数据的时候是启动一个后台服务进行数据获取的,整个数据获取有分多个阶段,Fresco通过producer划分这些阶段,比如缓存获取阶段、编码阶段、网络获取阶段,它会一个一个阶段去获取数据,如果producer1没有获取到数据就交给producer2进行获取数据以此类推下去,producer之间通过consumer返回数据,最终将数据返回到ui线程去。

画了个粗略的图:










0 0
原创粉丝点击