Fresco源码赏析 之 基本流程

转载请注明出处: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. */
	@Override
	public 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 first
		if (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 supplier
		if (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>
			@Override
			public DataSource<IMAGE> get() {
				return getDataSourceForRequest(imageRequest, callerContext, bitmapCacheOnly);//获取数据封装到数据提供者
			}

			@Override
			public 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.
 */
@ThreadSafe
public class SettableProducerContext implements ProducerContext 

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

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

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

/**
 * DataSource<CloseableReference<T>> backed by a Producer<CloseableReference<T>>
 *
 * @param <T>
 */
@ThreadSafe
public 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线程去。

画了个粗略的图:

时间: 2024-09-28 00:26:21

Fresco源码赏析 之 基本流程的相关文章

Fresco源码赏析 之 图片显示流程

转载请注明出处:http://blog.csdn.net/u014614038/article/details/51498068 上文大概将Fresco的基本流程通了一遍,就是Frosco是如何实现了只是简单调用了setImageUrl的方法后自动将所有事情做好,这里包含很多的流程,上文大概把这些流程过了一遍,这篇文章打算将接说一下上文没有说到的一些东西,就是拿到数据后它是如何处理的,是怎么显示出来的. 上文 Fresco源码赏析 之基本流程可以看这里: http://blog.csdn.net

Cocos2dx源码赏析(1)之启动流程与主循环

Cocos2dx源码赏析(1)之启动流程与主循环 我们知道Cocos2dx是一款开源的跨平台游戏引擎,而学习开源项目一个较实用的办法就是读源码.所谓,"源码之前,了无秘密".而笔者从事的也是游戏开发工作,因此,通过梳理下源码的脉络,来加深对Cocos2dx游戏引擎的理解. 既然,Cocos2dx是跨平台的,那么,就有针对不同平台运行的入口以及维持引擎运转的"死循环".下面,就分别从Windows.Android.iOS三个平台说明下Cocos2dx从启动到进入主循环

Fresco 源码浅析

前言 fresco是facebook主导的一个开源图片缓存库,从它提供的示例程序comparison来看,fresco貌似比其他的几个目前android主流的图片缓存库(glide,picasso,uil等)更快更节省内存.接下来就看看它到底是如何做到的. 一.背景: 1:lru与SoftReference那些年的爱恨情仇:很久很久以前,android的内存缓存还用SoftReference, 在2.3以后,垃圾回收机制被修改,软引用已不推荐用作缓存技术了,lru等才是正义.既然软引用已经不再推

Cocos2dx源码赏析(2)之渲染

Cocos2dx源码赏析(2)之渲染 这篇,继续从源码的角度来跟踪下Cocos2dx引擎的渲染过程,以此来梳理下Cocos2dx引擎是如何将精灵等元素显示在屏幕上的. 从上一篇对Cocos2dx启动流程的梳理中可知,Cocos2dx依靠通过各平台的入口启动引擎,并在循环中调用Director::mainLoop方法来维持引擎的各种逻辑: void Director::mainLoop() { if (_purgeDirectorInNextLoop) { _purgeDirectorInNext

Fresco源码解析 - 本地编译

第一次写专栏,如有表述不好或者理解错误的地方,请各位读者不吝赐教,本人一定虚心接受并第一时间改正. 作为专题第一篇,先从最简单的开始,顺便找找感觉. Fresco 是 facebook 在今年的 F8 大会上宣布开源的一个用于加载图片的库,它不仅支持多种图片文件格式,而且由于使用了pinned purgeables 技术,使得大图加载过程中产生OOM的概率大大降低,对开发者来说绝对是一件喜大普奔的事情,对于像天猫HD这样需要加载大量图片的APP来说也绝对是个福音. 下载代码 首先把源码从 Git

HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二)

HBase1.0.0源码分析之请求处理流程分析以Put操作为例(二) 1.通过mutate(put)操作,将单个put操作添加到缓冲操作中,这些缓冲操作其实就是Put的父类的一个List的集合.如下: private List<Row> writeAsyncBuffer = new LinkedList<>(); writeAsyncBuffer.add(m); 当writeAsyncBuffer满了之后或者是人为的调用backgroundFlushCommits操作促使缓冲池中的

openVswitch(OVS)源码分析之工作流程(哈希桶结构体的解释)

这篇blog是专门解决前篇openVswitch(OVS)源码分析之工作流程(哈希桶结构体的疑惑)中提到的哈希桶结构flex_array结构体成员变量含义的问题. 引用下前篇blog中分析讨论得到的flex_array结构体成员变量的含义结论: struct { int element_size; // 这是flex_array_part结构体存放的哈希头指针的大小 int total_nr_elements; // 这是全部flex_array_part结构体中的哈希头指针的总个数 int e

Spark SQL源码分析之核心流程

自从去年Spark Submit 2013 Michael Armbrust分享了他的Catalyst,到至今1年多了,Spark SQL的贡献者从几人到了几十人,而且发展速度异常迅猛,究其原因,个人认为有以下2点: 1.整合:将SQL类型的查询语言整合到 Spark 的核心RDD概念里.这样可以应用于多种任务,流处理,批处理,包括机器学习里都可以引入Sql. 2.效率:因为Shark受到hive的编程模型限制,无法再继续优化来适应Spark模型里. 前一段时间测试过Shark,并且对Spark

Fresco源码解析 - 创建一个ImagePipeline(一)

在Fresco源码解析 - 初始化过程分析章节中,我们分析了Fresco的初始化过程,两个initialize方法中都用到了 ImagePipelineFactory类. ImagePipelineFactory.initialize(context);会创建一个所有参数都使用默认值的ImagePipelineConfig来初始化ImagePipeline. ImagePipelineFactory.initialize(imagePipelineConfig)会首先用 imagePipelin