Fresco源码解析 - DataSource怎样存储数据
2015-05-01 19:00
393 查看
datasource是一个独立的
package,与FB导入的
guava包都在同一个工程内 -
fbcore。
datasource的类关系比较简单,一张类图基本就可以描述清楚它们间的关系。
DataSource是一个
interface, 功能与JDK中的
Future类似,但是相比于
Future,它的先进之处则在于 不仅仅只生产一个单一的结果,而是能够提供系列结果。
Unlike Futures, DataSource can issue a series of results, rather than just one.
最典型的用途就是渐进式加载图片时可以提供加载中的中间数据。
DataSubscriber和
DataSource构成了一个观察者模式。
Datasource提供了注册方法。
void subscribe(DataSubscriber<T> dataSubscriber, Executor executor);
通过
subscribe方法我们可以把
DataSubscriber注册成为
DataSource的观察者,然后当
DataSource的数据发生变化时,在
Executor中通知所有的观察者 -
DataSubscriber。
DataSubscriber会响应数据的四种变化。
onNewResult
onFailure
onCancellation
onProgressUpdate
使用
Executor来通知观察者是比较高明的,这样做可以让回调方法的执行线程交由
DataSubscriber来处理,增加了灵活性。
DataSource只是一个接口,没有提供任何实现,
AbstractDataSource实现了
DataSource后封装了一些基础的操作,例如 通知观察者,记录数据状态。
Datasource 的状态记录使用了一个枚举类型。
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, }
这三种状态保存在一个成员变量(
mDataSourceStatus)中。
@GuardedBy("this") private DataSourceStatus mDataSourceStatus;
AbstractDataSource构造时,会把
mDataSourceStatus设置为
IN_PROGRESS。
protected AbstractDataSource() { mIsClosed = false; mDataSourceStatus = DataSourceStatus.IN_PROGRESS; mSubscribers = new ConcurrentLinkedQueue<>(); }
所有的观察者(订阅者)会被放在一个列表中 -
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很重要的一点:不要产生内存泄露,也就是说,用过的资源一定要释放掉。
使用
DataSubscriber注册成为了观察者后,回调方法都会带回一个
DataSource的实例,如果请求已经结束后者失败了,拿到数据后一定要把
DataSource给
close掉,否则很容易造成 OOM。
BaseDataSubscriber就是为了防止OOM,它本身的设计也很巧妙。
在毁掉方法
onNewResult和
onFailure中加了一个
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是一个设计比较巧妙的借口,用途非常广泛。
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
checkArgument
checkState
checkNotNull
checkElementIndex
checkPositionIndex
checkPositionIndexes
如果 check 结果为 false, 则抛出异常。Fresco 的错误处理基本上是用异常做的。
相关文章推荐
- Fresco源码解析 - DataSource怎样存储数据
- Fresco源码解析 - DataSource怎样存储数据
- Fresco源码解析 - DataSource怎样存储数据
- Fresco源码解析 - DataSource怎样存储数据
- Fresco源码解析 - DataSource怎样存储数据
- Fresco源码解析 - DataSource怎样存储数据
- 动手改造Ibatis,使其支持文件系统存储数据列 之 源码下载编译和SqlMapConfig解析
- MyBatis源码解析(五)——DataSource数据源模块之非池型数据源
- 源码解析FragmentActivity重启后数据存储问题
- PHP 数据库中某个字段存储的数据是数组数据时,怎样获取并解析
- Android数据存储之JSON数据解析(输出部分)
- Android数据存储之JSON数据解析(读取部分)
- MySQL存储数据乱码的问题解析
- Android SharedPreferences数据存储原理解析及使用示例
- Android网络与数据存储——网络编程数据处理(网络请求解析Json,解析xml)
- 王家林亲授《DT大数据梦工厂》大数据实战视频“Scala深入浅出实战经典”视频、音频和PPT下载!第47讲:Scala多重界定代码实战及其在Spark中的应用源码解析
- 数据获取,解析,存储等知识的学习总结
- [python]通达信历史日线数据解析转换为CSV文件进行存储
- 及其简单的Rxjava+Retrofit+Fresco+ok,mvp小Dome解析数据
- Android 小项目之--数据存储【Shared Preferences】(附源码)