Fresco源码分析二

下面分析有关DataSource,DataSubscriber的部分:

1
2
3
4
5
6
7
8
9
10
11
public interface DataSource<T> {
boolean isClosed();
@Nullable T getResult();
boolean hasResult();
boolean isFinished();
boolean hasFailed();
@Nullable Throwable getFailureCause();
float getProgress();
boolean close();
void subscribe(DataSubscriber<T> dataSubscriber, Executor executor);
}

DataSource是什么?注释中说:An alternative to Java Futures for the image pipeline
Image pipeline 负责完成加载图像,变成Android设备可呈现的形式所要做的每个事情。(Fresco文档)
Futures代表了异步运算的结果。主要有三种功能:
1)判断任务是否完成;2)能够中断任务;3)能够获取任务执行结果。
可见DataSource中存在着对应这3个基本功能的方法。
不同的是Futures只能返回一个结果,而DataSource可以发布一系列的结果。
一个最好的例子就是在解码渐进式图片的时候,DataSource在最终图片解码完成之前,发布了一系列中间的图片解码效果。
所以,@Nullable T getResult()方法返回的是最新的异步计算结果,连续地调用这个函数可能回返回不同的结果。

1
public abstract class AbstractDataSource<T> implements DataSource<T> {}

AbstractDataSource首先具有一个描述数据源的枚举状态类:

1
2
3
4
5
6
7
8
9
10
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,
}

其他的数据源继承该类就可以同样管理自己的状态,并在状态改变的时候通知listeners。
其次,内部管理着一个ConcurrentLinkedQueue的实例mSubscribers,
private final ConcurrentLinkedQueue<Pair<DataSubscriber<T>, Executor>> mSubscribersConcurrentLinkedQueue是一个无边界的线程安全的基于链接节点的队列。该队列元素具有FIFO原则。当许多线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许 null 元素。
在subscribe()方法中:
注意shouldNotify 标志位

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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和dataSubscriber的一对多关系,还有DataSource自身不同状态对应着dataSubscriber的不同回调函数的关系,所以,controller内部管理一个dataSubscriber继而对Hierarchy做出相应的处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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);
}
}
});
}

而下面这个通知所有的DataSubscriber的方法,是在setResult(),setFailure(),close()中调用。
一旦有了最终的结果,无论是什么,都将通知所有的订阅者。

1
2
3
4
5
6
7
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);
}
}

此外,还有FirstAvailableDataSourceSupplier提供的FirstAvailableDataSource,提供一个可以首次获取到可用结果的数据源。内部维护着一个List>> ,按次序获取,只有当前的数据源失败了,或者没有获取到结果,才尝试下一个数据源。
还有IncreasingQualityDataSourceSupplier提供的IncreasingQualityDataSource,提供一个清晰度更高的数据源。内部同样维护着一个List>>,按次序数据源的清晰度逐渐降低。

1
2
3
4
5
6
7
8
9
10
11
12
13
public IncreasingQualityDataSource() {
final int n = mDataSourceSuppliers.size();
mIndexOfDataSourceWithResult = n;
mDataSources = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
DataSource<T> dataSource = mDataSourceSuppliers.get(i).get();
mDataSources.add(dataSource);
dataSource.subscribe(new InternalDataSubscriber(i), CallerThreadExecutor.getInstance());
if (dataSource.hasResult()) {
break;
}
}
}

PipelineDraweeController:

1
2
public class PipelineDraweeController
extends AbstractDraweeController<CloseableReference<CloseableImage>, ImageInfo> {}

Drawee controller是连接image pipeline和SettableDraweeHierarchy的桥梁。PipelineDraweeController通过数据源提供者,唯一标示controller的ID和callerContext初始化。

CloseableImage:实现了Closeable接口的图片包装类。
CloseableReference:对SharedReference的简单包装,实现了Closeable。
SharedReference:对类型是T的对象进行包装,使其具有引用计数的功能。
SharedReference类似C++的shared_ptr。
shared_ptr是一种智能指针,会记录有多少个shared_ptrs共同指向一个对象。这便是所谓的引用计数(reference counting)。一旦最后一个这样的指针被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动删除。
SharedReference的实现方式和C++并不相同,C++提供了一系列诸如拷贝构造函数和析构函数的语法糖,然而java并没有类似的东西。于是我们用addReference()和deleteReference() 函数替代,并且在任何情况下我们都要非常小心地运用。

语法糖(Syntactic Sugar),也叫糖衣语法,是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语。指的是,在计算机语言中添加某种语法,这种语法能使程序员更方便的使用语言开发程序,同时增强程序代码的可读性,避免出错的机会;但是这种语法对语言的功能并没有影响。
Java中的泛型,变长参数,自动拆箱/装箱,条件编译等都是。

SharedReference内部维护了一个IdentityHashMap的实例,用于存储对象和它的引用值:

1
2
3
4
5
6
private static final Map<Object, Integer> sLiveObjects = new IdentityHashMap<>();
private T mValue;
//引用值数
private int mRefCount;
//用于实现释放资源的接口,内部有一个函数release()
private final ResourceReleaser<T> mResourceReleaser;

初始化时将其引用计数值初始化为1,并调用addLiveReference(),将该对象和它的引用计数值添加到sLiveObjects中。

1
2
3
4
5
6
7
8
9
10
private static void addLiveReference(Object value) {
synchronized (sLiveObjects) {
Integer count = sLiveObjects.get(value);
if (count == null) {
sLiveObjects.put(value, 1);
} else {
sLiveObjects.put(value, count + 1);
}
}
}

removeLiveReference()方法与之相反。其余的代码也就很好理解了。

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
//是否可用
public synchronized boolean isValid() {
return mRefCount > 0;
}
public static boolean isValid(SharedReference<?> ref) {
return ref != null && ref.isValid();
}
public synchronized void addReference() {
ensureValid();
mRefCount++;
}
public void deleteReference() {
if (decreaseRefCount() == 0) {
T deleted;
synchronized (this) {
deleted = mValue;
mValue = null;
}
mResourceReleaser.release(deleted);
removeLiveReference(deleted);
}
}
private synchronized int decreaseRefCount() {
ensureValid();
Preconditions.checkArgument(mRefCount > 0);
mRefCount--;
return mRefCount;
}
private void ensureValid() {
if (!isValid(this)) {
throw new NullReferenceException();
}
}

CloseableReference代码:

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
//初始化引用计数	
public static @Nullable <T> CloseableReference<T> of(
@Nullable T t,
ResourceReleaser<T> resourceReleaser) {
if (t == null) {
return null;
} else {
return new CloseableReference<T>(t, resourceReleaser);
}
}
//添加对象引用,SharedReference引用数+1
public synchronized CloseableReference<T> clone() {
return new CloseableReference<T>(mSharedReference);
}
public synchronized T get() {
return mSharedReference.get();
}
//close()方法在finalize()中调用
public void close() {
synchronized (this) {
if (mIsClosed) {
return;
}
mIsClosed = true;
}
mSharedReference.deleteReference();
}

参考文章:https://github.com/desmond1121/Fresco-Source-Analysis

文章目录