datasource
是1个独立的 package
,与FB导入的guava
包都在同1个工程内 - fbcore
。
datasource
的类关系比较简单,1张类图基本就能够描写清楚它们间的关系。
DataSource
是1个 interface
, 功能与JDK中的Future
类似,但是相比于Future
,它的先进的地方则在于 不单单只生产1个单1的结果,而是能够提供系列结果。
Unlike Futures, DataSource can issue a series of results, rather than just one.
最典型的用处就是渐进式加载图片时可以提供加载中的中间数据。
DataSubscriber
和 DataSource
构成了1个视察者模式。
Datasource
提供了注册方法。
void subscribe(DataSubscriber<T> dataSubscriber, Executor executor);
通过 subscribe
方法我们可以把 DataSubscriber
注册成为 DataSource
的视察者,然后当 DataSource
的数据产生变化时,在 Executor
中通知所有的视察者 - DataSubscriber
。
DataSubscriber
会响应数据的4种变化。
使用Executor
来通知视察者是比较高明的,这样做可让回调方法的履行线程交由 DataSubscriber
来处理,增加了灵活性。
DataSource
只是1个接口,没有提供任何实现,AbstractDataSource
实现了 DataSource
后封装了1些基础的操作,例如 通知视察者,记录数据状态。
Datasource 的状态记录使用了1个枚举类型。
private enum DataSourceStatus {
// data source has not finished yet
IN_PROGRESS,
// data source has finished with success
SUCCESS,
// data source has finished with failure
FAILURE,
}
这3种状态保存在1个成员变量(mDataSourceStatus
)中。
@GuardedBy("this")
private DataSourceStatus mDataSourceStatus;
AbstractDataSource
构造时,会把 mDataSourceStatus
设置为 IN_PROGRESS
。
protected AbstractDataSource() {
mIsClosed = false;
mDataSourceStatus = DataSourceStatus.IN_PROGRESS;
mSubscribers = new ConcurrentLinkedQueue<>();
}
所有的视察者(定阅者)会被放在1个列表中 - mSubscribers
。
private final ConcurrentLinkedQueue<Pair<DataSubscriber<T>, Executor>> mSubscribers;
如果当前的数据要求没有关闭并且满足mDataSourceStatus == DataSourceStatus.IN_PROGRESS
时才能注册成功视察者,由于只有当数据产生变化的时候,视察者才有存在的意义。
@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());
}
}
如果 DataSource
有了新的数据或要求已结束掉或被取消掉,会通知视察者。
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);
}
}
private void notifyDataSubscriber(
final DataSubscriber<T> dataSubscriber,
final Executor executor,
final boolean isFailure,
final boolean isCancellation) {
executor.execute(
new Runnable() {
@Override
public void run() {
if (isFailure) {
dataSubscriber.onFailure(AbstractDataSource.this);
} else if (isCancellation) {
dataSubscriber.onCancellation(AbstractDataSource.this);
} else {
dataSubscriber.onNewResult(AbstractDataSource.this);
}
}
});
}
使用 DataSource
很重要的1点:不要产生内存泄漏,也就是说,用过的资源1定要释放掉。
使用 DataSubscriber
注册成了视察者后,回调方法都会带回1个 DataSource
的实例,如果要求已结束后者失败了,拿到数据后1定要把 DataSource
给 close
掉,否则很容易造成 OOM。
BaseDataSubscriber
就是为了避免OOM,它本身的设计也很奇妙。
在毁掉方法 onNewResult
和 onFailure
中加了1个 try - catch
, 在 try 的 block 中调用子类必须重载的 onNewResultImpl
方法,然后在 finally
的 block 中 close DataSource
。
DataSourceSubscriber.java
public abstract class BaseDataSubscriber<T> implements DataSubscriber<T> {
@Override
public void onNewResult(DataSource<T> dataSource) {
try {
onNewResultImpl(dataSource);
} finally {
if (dataSource.isFinished()) {
dataSource.close();
}
}
}
@Override
public void onFailure(DataSource<T> dataSource) {
try {
onFailureImpl(dataSource);
} finally {
dataSource.close();
}
}
@Override
public void onCancellation(DataSource<T> dataSource) {
}
@Override
public void onProgressUpdate(DataSource<T> dataSource) {
}
protected abstract void onNewResultImpl(DataSource<T> dataSource);
protected abstract void onFailureImpl(DataSource<T> dataSource);
}
IncreasingQualityDataSourceSupplier
和 FirstAvailableDataSourceSupplier
是 DataSource
的两种不同的数据存储情势,等后面用到了再做分析。
Supplier
是1个设计比较奇妙的借口,用处非常广泛。
A class that can supply objects of a single type. Semantically, this could be a factory, generator, builder, closure, or something else entirely. No guarantees are implied by this interface.
SettableDataSource
在 set
方法中使用 Guava
的 Preconditions
来做数据合法性检验,它与 DataSource
的区分也是仅此而已。
Preconditions
如果 check 结果为 false, 则抛出异常。Fresco 的毛病处理基本上是用异常做的。