博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Fresco源码解析 - DataSource怎样存储数据
阅读量:5020 次
发布时间:2019-06-12

本文共 6460 字,大约阅读时间需要 21 分钟。

 

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

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

fbcore的工程结构

datasource的类关系比较简单,一张类图基本就可以描述清楚它们间的关系。

datasource uml diagram


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

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

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


DataSubscriber 和 DataSource 构成了一个观察者模式

Datasource 提供了注册方法。

void subscribe(DataSubscriber
dataSubscriber, Executor executor);
  • 1

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

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

  1. onNewResult
  2. onFailure
  3. onCancellation
  4. 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,}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这三种状态保存在一个成员变量(mDataSourceStatus)中。

@GuardedBy("this")private DataSourceStatus mDataSourceStatus;
  • 1
  • 2

AbstractDataSource 构造时,会把 mDataSourceStatus 设置为 IN_PROGRESS

protected AbstractDataSource() {  mIsClosed = false;  mDataSourceStatus = DataSourceStatus.IN_PROGRESS;  mSubscribers = new ConcurrentLinkedQueue<>();}
  • 1
  • 2
  • 3
  • 4
  • 5

所有的观察者(订阅者)会被放在一个列表中 - mSubscribers

private final ConcurrentLinkedQueue
, Executor>> mSubscribers;
  • 1

如果当前的数据请求没有关闭并且满足mDataSourceStatus == DataSourceStatus.IN_PROGRESS时才能注册成功观察者,因为只有当数据发生变化的时候,观察者才有存在的意义。

  @Overridepublic void subscribe(final DataSubscriber
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()); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

如果 DataSource 有了新的数据或者请求已经结束掉或被取消掉,会通知观察者。

private void notifyDataSubscribers() {  final boolean isFailure = hasFailed();  final boolean isCancellation = wasCancelled();  for (Pair
, Executor> pair : mSubscribers) { notifyDataSubscriber(pair.first, pair.second, isFailure, isCancellation); }}
private
void
notifyDataSubscriber(
final DataSubscriber
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); } } });}
  • 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

使用 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
dataSource) {
try { onNewResultImpl(dataSource); }
finally {
if (dataSource.isFinished()) { dataSource.close(); } } }
@Override
public
void
onFailure(DataSource
dataSource) {
try { onFailureImpl(dataSource); }
finally { dataSource.close(); } }
@Override
public
void
onCancellation(DataSource
dataSource) { }
@Override
public
void
onProgressUpdate(DataSource
dataSource) { }
protected
abstract
void
onNewResultImpl(DataSource
dataSource);
protected
abstract
void
onFailureImpl(DataSource
dataSource);}
  • 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

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 的错误处理基本上是用异常做的。

转载于:https://www.cnblogs.com/wuwuwu/p/6162636.html

你可能感兴趣的文章
Bypass caps, decoupling caps和bulk caps
查看>>
nginx负载均衡
查看>>
查找cv2安装内容
查看>>
开源FTP/SFTP客户端 FileZilla v3.31.0 绿色便携版
查看>>
Windows下MongoDB安装配置
查看>>
Lua-面向对象中函数使用时冒号(:)和点(.)的区别
查看>>
【IBM Tivoli Identity Manager 学习文档】12 Workflow的设计
查看>>
【Java学习笔记】对象的序列化和反序列化
查看>>
sqlite入门基础(一):sqlite3_open,sqlite3_exec,slite3_close
查看>>
IE 下 log 调试的一点不同
查看>>
Day 7 深copy和浅Copy
查看>>
Spark SQL External Data Sources JDBC官方实现写测试
查看>>
MySQL数据库的事物隔离级别
查看>>
delphi 基础之四 delphi 组织结构
查看>>
python实例二
查看>>
数组去重方法(转载)
查看>>
hibernate映射之单向多对一
查看>>
SQL Server中的行转列
查看>>
在iOS应用中直接打开系统的“设置”
查看>>
github前夜-版本控制(VersionControl)
查看>>