前言
项目中使用的是 Fresco, 很基础的一个图片加载框架, 到处都在使用, 所以还是有必要去了解以下。 通过对 Fresco 的大致源码阅读, 可能刚刚开始会很蒙, 因为不管是代码风格还是规模, 甚至命名, 来回跳来跳去, 确实不太容易。
主要对其的大致流程进行梳理和整理。 太细的细节我也没有太清晰的深入的看, 后续有时间会把细节看了。 现在主要关注流程和思想。
博客参考:https://juejin.cn/post/6844903559280984071
基本写法
1
| simpleDraweeView.setImageURI("url")
|
我们从最简单的开始。 注意这里我们仅仅分析流程。
源码分析
需要知道的基本概念和作用
- SimpleDraweeView: 最终继承 ImageView。
- Hierarchy: 绘制图片等。
- Controller: 控制数据获取等。
- DraweeHolder: SimpleDraweeView 持有, 自身持有 Hierarchy 和 Controller。
- DataSource: 一个图片请求一个 DataSource, 其内部包含 Producer 串。
- Producer: 对图片的每一个操作,比如请求网络获取数据、 从内存、 从磁盘中获取图片等。
- Consumer: 每一个 Producer 对于一个 Consumer, 接收底部的结果自己处理下, 把自己处理的结果像上面抛。 可以理解为一个回调。
图片绑定展示
从最简单的来, 我们看看图片是怎么展示的, 因为 SimpleDraweeView 是最后都是继承的 ImageView, 所以图片最后肯定是设置在 ImageView 了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public void setController(@Nullable DraweeController draweeController) { super.setImageDrawable(mDraweeHolder.getTopLevelDrawable()); }
public @Nullable Drawable getTopLevelDrawable() { return mHierarchy == null ? null : mHierarchy.getTopLevelDrawable(); }
public Drawable getTopLevelDrawable() { return mTopLevelDrawable; }
|
可以我们看到设置了 ImageView 的 drawble。 设置的是 Hierarchy 的 topLevelDrawable。 所以 ImageView 的绘制是交给 Hierarchy 处理的。 至于 Hierarchy 是展示各种图片的呢, 可以点进去看看, 其是它是一层一层的, 其中 mActualImageWrapper 就是成功后设置的图片层。
图片的请求
图片请求的逻辑在 Controller 中, 我们一步步的看下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
| public void setImageURI(Uri uri, @Nullable Object callerContext) { DraweeController controller = mControllerBuilder .setCallerContext(callerContext) .setUri(uri) .setOldController(getController()) .build(); setController(controller); }
public AbstractDraweeController build() { return buildController(); }
protected AbstractDraweeController buildController() { AbstractDraweeController controller = obtainController(); return controller; }
protected PipelineDraweeController obtainController() { try { PipelineDraweeController controller; controller.initialize( obtainDataSourceSupplier(controller, controllerId), controllerId, getCacheKey(), getCallerContext(), mCustomDrawableFactories, mImageOriginListener); return controller; } finally { } }
protected Supplier<DataSource<IMAGE>> obtainDataSourceSupplier( final DraweeController controller, final String controllerId) { Supplier<DataSource<IMAGE>> supplier = null; if (mImageRequest != null) { supplier = getDataSourceSupplierForRequest(controller, controllerId, mImageRequest); } else if (mMultiImageRequests != null) {
} return supplier; }
protected Supplier<DataSource<IMAGE>> getDataSourceSupplierForRequest( final DraweeController controller, String controllerId, REQUEST imageRequest) { return getDataSourceSupplierForRequest( controller, controllerId, imageRequest, CacheLevel.FULL_FETCH); }
protected Supplier<DataSource<IMAGE>> getDataSourceSupplierForRequest( final DraweeController controller, final String controllerId, final REQUEST imageRequest, final CacheLevel cacheLevel) { final Object callerContext = getCallerContext(); return new Supplier<DataSource<IMAGE>>() { @Override public DataSource<IMAGE> get() { return getDataSourceForRequest( controller, controllerId, imageRequest, callerContext, cacheLevel); }
@Override public String toString() { return Objects.toStringHelper(this).add("request", imageRequest.toString()).toString(); } }; }
protected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest( DraweeController controller, String controllerId, ImageRequest imageRequest, Object callerContext, AbstractDraweeControllerBuilder.CacheLevel cacheLevel) { return mImagePipeline.fetchDecodedImage( imageRequest, callerContext, convertCacheLevelToRequestLevel(cacheLevel), getRequestListener(controller), controllerId); }
public DataSource<CloseableReference<CloseableImage>> fetchDecodedImage( ImageRequest imageRequest, @Nullable Object callerContext, ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit, @Nullable RequestListener requestListener, @Nullable String uiComponentId) { try { Producer<CloseableReference<CloseableImage>> producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest); return submitFetchRequest( producerSequence, imageRequest, lowestPermittedRequestLevelOnSubmit, callerContext, requestListener, uiComponentId); } catch (Exception exception) { return DataSources.immediateFailedDataSource(exception); } }
|
其中 getDecodedImageProducerSequence 就是得到该请求的 Producer 串。 我们先讲下 Producer 及 Consumer 是什么, 是怎么的原理。
怎么说呢 Producer 和 Consumer 有点像装饰着模式, 但也不全对哈。 每一个对图片的处理或者获取都是一个 Producer, Consumer 看着是一个消费者, 也是也就是一个回调而已, 让自己可以通知上面结果, 也可以拿到下面的结果反馈。 简单的举个例子哈。
我们都知道图片加载框架基本都是三级缓存的, 那么我们就以这个为例简单的说下 Fresco 中的处理逻辑。 我们先明确, 我们先去内存中获取, 获取到了,就返回出去, 如果没有就去磁盘里获取, 如果获取到了, 就返回, 返回前肯定要加入到内存中, 如果磁盘还未获取到的话, 就去网络获取, 获取到了就返回, 返回前会存磁盘, 存内存。
OK 根据上面的逻辑, 我们伪代码实现下哈。 (自己根据 Fresco 的逻辑简易伪代码描述哈, 只是描述处理逻辑, 跟 Fresco 的代码没有任何关系哈)
我们先看下 Consumer 和 Producer 协议, 仅仅就是一个回调。
1 2 3 4 5 6 7 8 9
| interface Consumer { fun onSuccess(image) }
interface Producer { fun handle(Consumer) }
|
我们看下各个 Producer 怎么写呢
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
| class MemoryProducer: Producer { private lateinit var mProducer: Producer MemoryProducer(Producer producer) { this.mProducer = producer } override fun handle(consumer: Consumer) { if(内存中存在这个图片) { consumer.onSuccess(image) return } mProducer.handle(MemoryConsumer(consumer)) } private class MemoryConsumer: Consumer { private lateinit var mConsumdr: Consumer MemoryConsumer(consumer: Consumer) { this.mConsumer = consumer } override fun onSuccess(image) { 1. 保存到内存中 2. 回调出去 mConsumer.onSuccess(image) } } }
class DiskProducer: Producer { private lateinit var mProducer: Producer DiskProducer(Producer producer) { this.mProducer = producer } override fun handle(consumer: Consumer) { if(磁盘中存在这个图片) { consumer.onSuccess(image) return } mProducer.handle(DiskConsumer(consumer)) } private class DiskConsumer: Consumer { private lateinit var mConsumdr: Consumer DiskConsumer(consumer: Consumer) { this.mConsumer = consumer } override fun onSuccess(image) { 1. 保存到磁盘中 2. 回调出去 mConsumer.onSuccess(image) } } }
class NetProducer: Producer { override fun handle(consumer: Consumer) { if(从网络获取成功了) { consumer.onSuccess(image) } } }
|
通过上面的伪代码实现中很清晰的看出其功能, 我们看看怎么把他们串起来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
val finalResult = object: Consumer { override fun onSuccess(image) { } }
val netProducer = NetProducer() val diskProducer = DiskProducer(netProducer) val memoryPrducer = MemoryProducer(disProducer)
memoryProducer.handle(finalResult)
|
通过上面的简易伪代码, 你明白了吗?!
ok, 上面的伪代码看懂后, 我们就直接往下看, 跨越太远, 再把分析的代码最后复制下来
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public DataSource<CloseableReference<CloseableImage>> fetchDecodedImage( ImageRequest imageRequest, @Nullable Object callerContext, ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit, @Nullable RequestListener requestListener, @Nullable String uiComponentId) { try { Producer<CloseableReference<CloseableImage>> producerSequence = mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest); return submitFetchRequest( producerSequence, imageRequest, lowestPermittedRequestLevelOnSubmit, callerContext, requestListener, uiComponentId); } catch (Exception exception) { return DataSources.immediateFailedDataSource(exception); } }
|
其中 getDecodedImageProducerSequence 就是获取了 Producer 串, 我们就在分析了。 我们看下 submitFetchRequest 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| private <T> DataSource<CloseableReference<T>> submitFetchRequest( Producer<CloseableReference<T>> producerSequence, ImageRequest imageRequest, ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit, @Nullable Object callerContext, @Nullable RequestListener requestListener, @Nullable String uiComponentId) { try { return CloseableProducerToDataSourceAdapter.create( producerSequence, settableProducerContext, requestListener2); } catch (Exception exception) { } finally { } }
public static <T> DataSource<CloseableReference<T>> create( Producer<CloseableReference<T>> producer, SettableProducerContext settableProducerContext, RequestListener2 listener) { CloseableProducerToDataSourceAdapter<T> result = new CloseableProducerToDataSourceAdapter<T>(producer, settableProducerContext, listener); return result; }
protected AbstractProducerToDataSourceAdapter( Producer<T> producer, SettableProducerContext settableProducerContext, RequestListener2 requestListener) { producer.produceResults(createConsumer(), settableProducerContext); }
|
看到 producer.produceResults(createConsumer(), settableProducerContext); 这一行了吧, 这个就是开始执行 Producer 串了哈。 我们现在只关心下拿到数据后回调出来做了什么事情。 也就是看看 createConsumer() 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| private Consumer<T> createConsumer() { return new BaseConsumer<T>() { @Override protected void onNewResultImpl(@Nullable T newResult, @Status int status) { AbstractProducerToDataSourceAdapter.this.onNewResultImpl( newResult, status, mSettableProducerContext); } @Override protected void onFailureImpl(Throwable throwable) { AbstractProducerToDataSourceAdapter.this.onFailureImpl(throwable); } @Override protected void onCancellationImpl() { AbstractProducerToDataSourceAdapter.this.onCancellationImpl(); } @Override protected void onProgressUpdateImpl(float progress) { AbstractProducerToDataSourceAdapter.this.setProgress(progress); } }; }
protected void onNewResultImpl(@Nullable T result, int status, ProducerContext producerContext) { boolean isLast = BaseConsumer.isLast(status); if (super.setResult(result, isLast, getExtras(producerContext))) { if (isLast) { mRequestListener.onRequestSuccess(mSettableProducerContext); } } }
|
我们看下 super.setResult() 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| protected boolean setResult( @Nullable T value, boolean isLast, @Nullable Map<String, Object> extras) { setExtras(extras); boolean result = setResultInternal(value, isLast); if (result) { notifyDataSubscribers(); } return result; }
private void notifyDataSubscribers() { final boolean isFailure = hasFailed(); final boolean isCancellation = wasCancelled(); for (Pair<DataSubscriber<T>, Executor> pair : mSubscribers) { notifyDataSubscriber(pair.first, pair.second, isFailure, isCancellation); } }
protected void notifyDataSubscriber( final DataSubscriber<T> dataSubscriber, final Executor executor, final boolean isFailure, final boolean isCancellation) { Runnable runnable = new Runnable() { @Override public void run() { if (isFailure) { dataSubscriber.onFailure(AbstractDataSource.this); } else if (isCancellation) { dataSubscriber.onCancellation(AbstractDataSource.this); } else { dataSubscriber.onNewResult(AbstractDataSource.this); } } }; final DataSourceInstrumenter instrumenter = getDataSourceInstrumenter(); if (instrumenter != null) { runnable = instrumenter.decorateRunnable(runnable, "AbstractDataSource_notifyDataSubscriber"); } executor.execute(runnable); }
|
看着是通过 dataSubscriber 反馈回调出去了, 我们来看着这个 dataSubscriber 是啥。
首先我们直观的先去找, 就是 mSubscribers 成员变量循环然后回调出去的, 我们看看这个 mSubscribers 是什么时候 add 的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Override public void subscribe(final DataSubscriber<T> dataSubscriber, final Executor executor) { Preconditions.checkNotNull(dataSubscriber); Preconditions.checkNotNull(executor); boolean shouldNotify;
synchronized (this) { if (mIsClosed) { return; }
if (mDataSourceStatus == DataSourceStatus.IN_PROGRESS) { mSubscribers.add(Pair.create(dataSubscriber, executor)); }
shouldNotify = hasResult() || isFinished() || wasCancelled(); }
if (shouldNotify) { notifyDataSubscriber(dataSubscriber, executor, hasFailed(), wasCancelled()); } }
|
发现 add 的时候只有这个地方进行了 add。 那么我们点下这个方法我们看看是哪里调用的呢?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| protected void submitRequest() { final DataSubscriber<T> dataSubscriber = new BaseDataSubscriber<T>() { @Override public void onNewResultImpl(DataSource<T> dataSource) { boolean isFinished = dataSource.isFinished(); boolean hasMultipleResults = dataSource.hasMultipleResults(); float progress = dataSource.getProgress(); T image = dataSource.getResult(); if (image != null) { onNewResultInternal( id, dataSource, image, progress, isFinished, wasImmediate, hasMultipleResults); } else if (isFinished) { onFailureInternal(id, dataSource, new NullPointerException(), true); } } @Override public void onFailureImpl(DataSource<T> dataSource) { onFailureInternal(id, dataSource, dataSource.getFailureCause(), true); } @Override public void onProgressUpdate(DataSource<T> dataSource) { boolean isFinished = dataSource.isFinished(); float progress = dataSource.getProgress(); onProgressUpdateInternal(id, dataSource, progress, isFinished); } }; mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor); }
|
发现是在 AbstractDraweeController 中 submitRequest 调用的。 继续点 submitRequest。 可以发现只有两个地方, 一个是点击相关的, 这个是用户点击加载的, 比如重新加载, 这个我们不分析了, 我们看看另一个地方的调用。
1 2 3 4 5 6 7
| public void onAttach() { mIsAttached = true; if (!mIsRequestSubmitted) { submitRequest(); } }
|
在 AbstractDraweeController onAttach 时调用的。 那 Controller 的 onAttach 是什么时候调用的。
1 2 3 4 5 6 7
| private void attachController() { mIsControllerAttached = true; if (mController != null && mController.getHierarchy() != null) { mController.onAttach(); } }
|
当然也可以再次点击下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public void setController(@Nullable DraweeController draweeController) { boolean wasAttached = mIsControllerAttached; if (wasAttached) { detachController(); } if (isControllerValid()) { mEventTracker.recordEvent(Event.ON_CLEAR_OLD_CONTROLLER); mController.setHierarchy(null); } mController = draweeController; if (mController != null) { mEventTracker.recordEvent(Event.ON_SET_CONTROLLER); mController.setHierarchy(mHierarchy); } else { mEventTracker.recordEvent(Event.ON_CLEAR_CONTROLLER); } if (wasAttached) { attachController(); } }
|
这个方法熟悉吗? 哈哈, 对了就是在设置 url 去加载图片时去设置了 controller
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| simpleDraweeView.setImageURI("url")
public void setImageURI(Uri uri, @Nullable Object callerContext) { DraweeController controller = mControllerBuilder .setCallerContext(callerContext) .setUri(uri) .setOldController(getController()) .build(); setController(controller); }
public void setController(@Nullable DraweeController draweeController) { mDraweeHolder.setController(draweeController); super.setImageDrawable(mDraweeHolder.getTopLevelDrawable()); }
|
哈哈, 串起来了吧, 所以也可以知道另一方面只有在设置 Controller 才展示数据的哈。
可能你有点疑惑, 就是加载图片是异步的, 但是看着这个 setController 是在主线程设置回调了, 那么怎么可以在加载图片回来后保证 setController 过了呢。 不用担心这个, 你想想, 如果图片回调过来后, 还没有 setController, 那么 mSubscribers 就为空, 所以不会更新图片, 但是图片已经加载好了哈这个时候, 在 setController 时又会在订阅 DataSource 去判断是否有结果, 有的话再次更新。 如果是setController 比异步加载图片先返回的话, 那么直接就异步回来后通过 mSubscribers 去通知更新了哈。
最后附上张丑图
