@linux1s1s
2016-07-19T11:16:08.000000Z
字数 5251
阅读 1838
Fresco
2016-07
转载 作者:Desmond
在这一章中,我将分析数据源DataSource
的生成过程及它的作用。
根据Uri生成Producer
和DataSource
的过程概览:
以上的时序图是精简过的,意在表达各个组件之间的调用顺序和功能。
在第三章末尾我们讲到DraweeControllerBuilder
会根据Uri初始化DataSource
的Supplier,那么现在来看看是怎么初始化的。
首先会根据各种情况判断生成不同的DataSource:
protected Supplier<DataSource<IMAGE>> obtainDataSourceSupplier() {
//...
if (mImageRequest != null) {
supplier = getDataSourceSupplierForRequest(mImageRequest);
} else if (mMultiImageRequests != null) {
supplier = getFirstAvailableDataSourceSupplier(mMultiImageRequests);
}
我们看到Fresco会根据是否有多个图片请求,如果有,则会取多个图片请求中最先能请求到的作为DataSource。
if (supplier != null && mLowResImageRequest != null) {
List<Supplier<DataSource<IMAGE>>> suppliers = new ArrayList<>(2);
suppliers.add(supplier);
suppliers.add(getDataSourceSupplierForRequest(mLowResImageRequest));
supplier = IncreasingQualityDataSourceSupplier.create(suppliers);
}
在之后会判断是否有提供低分辨率的图片,如果有,则创建一个清晰度逐渐提高的DataSource(默认只有两级清晰度)。更多关于多图请求的内容参照多图请求及图片复用。
在此我们就分析根据一个ImageRequest获取DataSource的过程,获取其他种类DataSource都是通过它实现的。
protected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest(
ImageRequest imageRequest,
Object callerContext,
boolean bitmapCacheOnly) {
if (bitmapCacheOnly) {
return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext);
} else {
return mImagePipeline.fetchDecodedImage(imageRequest, callerContext);
}
}
这个函数给我们传递了两个信息:
bitmapCacheOnly
(是否只从已解码的内存缓存中获取数据)来获取不同的DataSource。那我们就来看看它不限制缓存级别的时候是怎么处理的(这种情况下会包括bitmapCacheOnly
时候的内容)。
public DataSource<CloseableReference<CloseableImage>> fetchDecodedImage(
ImageRequest imageRequest,
Object callerContext) {
try {
Producer<CloseableReference<CloseableImage>> producerSequence =
mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
return submitFetchRequest(
producerSequence,
imageRequest,
ImageRequest.RequestLevel.FULL_FETCH,
callerContext);
} catch (Exception exception) {
return DataSources.immediateFailedDataSource(exception);
}
}
我们发现它会首先根据传入的ImageRequest
产生一个Producer
,它为不同ImageRequest提供了不同的数据传送的管道。(关于Producer具体见Fresco源码分析(5) - Producer)
在submitFetchRequest
函数中做了三件事:
ImageRequest
的LowestPermittedRequestLevel
和传入的RequestLevel
中最高的一级作为此次数据获取的最高缓存获取层;ImageRequest
、本次请求的唯一标识、ImageRequestListener
(提供ImageRqeuest事件的回调)、是否需要渐进式加载图片等信息封装进SettableProducerContext
。AbstractproducerToDataSourceAdapter
,它实际上是一种DataSource
,在这个过程中会让producer通过SettableProducerContext
获取数据。至此我们就获取了所需要的DataSource,并将它设置给DraweeController。
上一节中我们获取了一个AbstractproducerToDataSourceAdapter
作为DataSource
,你可能对它的功能不太理解,这一节将介绍各类DataSource的功能。
DataSource的原型
public interface DataSource<T> {
public boolean isClosed();
//是否得到结果
boolean hasResult();
//获取现在得到的结果
@Nullable T getResult();
//是否结束
boolean isFinished();
//是否失败
boolean hasFailed();
//获取失败原因
@Nullable Throwable getFailureCause();
//获取加载进度
float getProgress();
//释放资源
boolean close();
//绑定DataSubScriber
void subscribe(DataSubscriber<T> dataSubscriber, Executor executor);
}
Fresco接着实现了一个基础类AbstractDataSource
,维持着IN_PROGRESS、SUCCESS、FAILURE三种状态。它除了实现close
、subscribe
的之外,添加了这几个重要函数及其实现:
setResultInternal(@Nullable T value, boolean isLast)
当DataSource关闭或状态非IN_PROGRESS时返回false,否则设置Result并返回ture,若isLast为true,则设置状态为SUCCESS;setFailureInternal(Throwable throwable)
当DataSource关闭或状态非IN_PROGRESS时返回false,否则设置失败原因、状态为FAILURE并返回true;setProgressInternal(float progress)
当DataSource关闭或状态非IN_PROGRESS时返回false,若目标进度小于已有进度也返回false,否则更新进度并返回true;notifyDataSubscriber(DataSubscriber<T> subscriber, Executor executor, boolean isFailure, boolean isCancellation)
在指定的Executor上根据isFailure、isCancellation调用DataSubscriber的对应函数(若都为false即成功加载),由此更新数据;notifyDataSubscribers()
通知所有绑定的DataSubscriber更新数据;setResult
/setFailure
/setProgress
调用对应setXXXInternal
,当其返回true时,调用notifyDataSubscribers()
。AbstractProducerToDataSourceAdapter
也是一种DataSource,它继承AbstractDataSource
,包装了Producer取数据的过程,非常重要,所以单独列出来。
它在创造过程中主要做了两件事:
produceResults(Consumer consumer, ProducerContext context)
,让它开始加载数据。我们用一个直观的图来看看当Producer产生新结果(newResult)时的调用顺序是什么样的:
当失败(Failure)、取消(Cancel)、更新进度(ProgressUpdate)时的操作流程是类似的。我们可以看出,AbstractProducerToDataSourceAdapter
是连接Producer与DataSource的纽带。
AbstractProducerToDataSourceAdapter的构造方法是protected,只能通过继承的类提供的办法来构造它。以下是两个继承了AbstractProducerToDataSourceAdapter
的类:
CloseableProducerToDataSourceAdapter
提供create
方法创建实例,实现了closeResult
方法,会在AbstractDataSource
销毁时同时销毁收到的Result,是主要使用的DataSouce;ProducerToDataSourceAdapter
提供create
方法创建实例,没有实现别的方法。此DataSource仅仅用于预加载图片!它内部维持着一个AbstractDataSource
(可以说是CloseableProducerToDataSourceAdapter
)列表,DataSource提供数据的清晰度由后往前递增。
它会为列表中的每一个DataSource绑定一个DataSubscriber(IncreasingQualityDataSourceSupplier.InternalDataSubscriber
),它负责保证每次只能获取清晰度更高的DataSource数据,获取数据同时会销毁数据清晰度更低的DataSource。
它内部维持着一个AbstractDataSource
(可以说是CloseableProducerToDataSourceAdapter
)列表,它会返回这里面首先能获取到数据的DataSource。
同样,它也会为列表中的DataSource绑定DataSubscriber(FirstAvailableDataSourceSupplier.InternalDataSubscriber
),如果数据加载成功,那么就设定指定DataSource为目标DataSource;如果加载数据失败,则跳转到列表下一个DataSource继续尝试加载。
它继承AbstractDataSource,并将重写settResult
、setFailure
、setProgress
在内部调用父类的相应函数,但是修饰符变成了public(原来是protected)。即使用SettableDataSource
时可以在外部调用这三个函数设置DataSource状态。一般用于在获取DataSource失败时直接产生一个设置为Failure的DataSource。
关于数据源的其他内容,可以参考数据源/订阅数据源。