国内最全IT社区平台 联系我们 | 收藏本站
华晨云阿里云优惠2
您当前位置:首页 > php开源 > 综合技术 > Fresco源码解析 - DataSource怎样存储数据

Fresco源码解析 - DataSource怎样存储数据

来源:程序员人生   发布时间:2015-05-26 08:32:42 阅读次数:3235次

datasource是1个独立的 package,与FB导入的guava包都在同1个工程内 - fbcore

fbcore的工程结构

datasource的类关系比较简单,1张类图基本就能够描写清楚它们间的关系。

datasource uml diagram


DataSource 是1个 interface, 功能与JDK中的Future类似,但是相比于Future,它的先进的地方则在于 不单单只生产1个单1的结果,而是能够提供系列结果

Unlike Futures, DataSource can issue a series of results, rather than just one.

最典型的用处就是渐进式加载图片时可以提供加载中的中间数据。


DataSubscriberDataSource 构成了1个视察者模式

Datasource 提供了注册方法。

void subscribe(DataSubscriber<T> dataSubscriber, Executor executor);

通过 subscribe 方法我们可以把 DataSubscriber 注册成为 DataSource 的视察者,然后当 DataSource 的数据产生变化时,在 Executor 中通知所有的视察者 - DataSubscriber

DataSubscriber 会响应数据的4种变化。

  1. onNewResult
  2. onFailure
  3. onCancellation
  4. onProgressUpdate

使用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定要把 DataSourceclose 掉,否则很容易造成 OOM。

BaseDataSubscriber 就是为了避免OOM,它本身的设计也很奇妙。

在毁掉方法 onNewResultonFailure 中加了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); }

IncreasingQualityDataSourceSupplierFirstAvailableDataSourceSupplierDataSource 的两种不同的数据存储情势,等后面用到了再做分析。


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.


SettableDataSourceset 方法中使用 GuavaPreconditions 来做数据合法性检验,它与 DataSource 的区分也是仅此而已。

Preconditions

  • checkArgument
  • checkState
  • checkNotNull
  • checkElementIndex
  • checkPositionIndex
  • checkPositionIndexes

如果 check 结果为 false, 则抛出异常。Fresco 的毛病处理基本上是用异常做的。

生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠
程序员人生
------分隔线----------------------------
分享到:
------分隔线----------------------------
关闭
程序员人生