转载请注明出处: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线程去。
画了个粗略的图: