您的位置:首页 > 其它

Fresco正传(4):DraweeController分析

2015-11-13 14:25 253 查看

前言

一口气写了好多了,先配张美女图,放松下眼睛。



言归正传,在总览的文章中就分析过,
DraweeController
是控制数据逻辑的核心,数据的请求也会在这部分发出。但是,一口气写下来,估计内容会太多,所以本篇博客只分析
DraweeController
的体系结构以及内部方法和介绍一些延伸性的东西。至于,如何发出请求获取图片的,后续博客再分析。

当然还是先给出
DraweeController
的继承体系,看看能推测出来一些什么。



DraweeController
不用说,肯定是一些抽象共性的东西。而
AbstractDraeeController
应该是在抽象的基础上,封装了一些共性操作,这也非常符合现在开发技术:通过接口抽象,并给出抽象的共性操作实现,具体怎么做、做什么交给你。那么
VolleyDraweeController
PipelineDraweeController
就应该是具体使用什么样的方法来做事了。

正文

自上而下的分析类以及类中典型的方法。

DraweeController

先分析下类注释,看看能发现什么:

DraweeController
会被
DraweeView
所使用。

DraweeView
会转发事件给
DraweeController
,而
DraweeController
会基于事件控制
DraweeHierarchy
顶层视图的切换。

简单几句话描述了
DraweeController
身为控制器的核心作用:逻辑处理。

往下看,
onAttach()
是不是很眼熟,当
DraweeView
包含的层级结构被附加在window上时被调用。

还记得在第二篇分析中,博文最后分析
DrwaeeHolder
attachController()
方法吗?没错,哪里调用的就是这个
onAttach()
方法。而且,我们说过在调用
attachController()
之所以会有这么多限制条件,肯定是由于这里有重要的逻辑发生。在
onAttach()
方法中获取数据源、拿到图片、并最后通过观察者设置实际显示的图片,具体的细节稍后再说。

AbstractDraweeController

在正式分析
AbstractDraweeController
之前还有个小插曲,那就是
DataSource
DataSubscriber
的关系。

如果你有关心
RxJava
那么你一定看过这篇文章:给 Android 开发者的 RxJava 详解
RxJava
是响应式编程的一部分,而响应式编程则充分利用了和扩展了观察者模式,使
RxJava
非常强大。

如果你有观察者的基础,那么你一定一眼就明白
DataSource
是被观察者,而
DataSubscriber
是观察者。在被观察者存储着观察者的数据集合,以用来及时通知事件。

public interface DataSource<T> {

/**
* 通知订阅者数据源状态的改变
* Subscribe for notifications whenever the state of the DataSource changes.
*/
void subscribe(DataSubscriber<T> dataSubscriber, Executor executor);
}


在来看一下
DataSubscriber
都有什么。值得一提的是,
DataSource
使用完后,必须要求被安全的关闭。

public interface DataSubscriber<T> {
void onNewResult(DataSource<T> dataSource);
void onFailure(DataSource<T> dataSource);
void onCancellation(DataSource<T> dataSource);
void onProgressUpdate(DataSource<T> dataSource);
}


所以,就有了
BaseDataSubscriber
类,实现了
DataSubscriber
接口,并在finally中安全关闭了数据源。 这个类
AbstractDraweeController
中会用到。

public abstract class BaseDataSubscriber<T> implements DataSubscriber<T> {

@Override
public void onNewResult(DataSource<T> dataSource) {
try {
onNewResultImpl(dataSource);
} finally {
if (dataSource.isFinished()) {
dataSource.close();
}
}
}

// ...

protected abstract void onNewResultImpl(DataSource<T> dataSource);

protected abstract void onFailureImpl(DataSource<T> dataSource);
}


正式开始
AbstractDraweeController
的分析。先看看类注释能告诉我们什么:

实现了一些通用的功能,并不涉及具体是怎样抓取图片的。

所有的方法都应该在UI线程调用。

再看看构造方法,在其中调用了
init()
方法,主要是做了一些状态的初始化:

取消延时释放

重置启动状态

重新初始化重试、手势、监听器

清除旧的层次结构

重置状态常量

虽然代码很多,但是都可以忽略不计的逻辑,实际上我们也不关心这些。接下来就看看非常重要的
onAttach()
方法。

@Override
public void onAttach() {
Preconditions.checkNotNull(mSettableDraweeHierarchy);
mDeferredReleaser.cancelDeferredRelease(this);
mIsAttached = true;
if (!mIsRequestSubmitted) {
submitRequest();
}
}


检查
SettableDraweeHierarchy
可设置的层次机构不许为NULL,否则直接报异常。是否是请求状态,是就调用
submitRequest()
方法发送请求。

从这里开始会完成一些列复杂的操作,先看一张图吧。



protected void submitRequest() {
...
mSettableDraweeHierarchy.setProgress(0, true);
...
mDataSource = getDataSource();
...
// 此处以第一次请求为例,所以wasImmediate为false
final boolean wasImmediate = mDataSource.hasResult();

//------------创建dataSubscriber的匿名内部类,交由AbstractDraweeController处理
final DataSubscriber<T> dataSubscriber =
new BaseDataSubscriber<T>() {
@Override
public void onNewResultImpl(DataSource<T> dataSource) {
// isFinished must be obtained before image, otherwise we might set intermediate result
// as final image.
boolean isFinished = dataSource.isFinished();
float progress = dataSource.getProgress();
T image = dataSource.getResult();
if (image != null) {
onNewResultInternal(id, dataSource, image, progress, isFinished, wasImmediate);
} else if (isFinished) {
onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true);
}
}

@Override
public void onFailureImpl(DataSource<T> dataSource) {
onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true);
}

@Override
public void onProgressUpdate(DataSource<T> dataSource) {
boolean isFinished = dataSource.isFinished();
float progress = dataSource.getProgress();
onProgressUpdateInternal(id, dataSource, progress, isFinished);
}
};

// 给数据源注册观察者
mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor);
}


整个方法做了如下的事情:

设置加载进度为0

获取数据源,这句话是核心语句。并且
getDataSource()
是个抽象方法,交给子类具体处理。

创建数据源观察者,并在内部类的
onNewResultImpl()
方法,调用
AbstarctDraweeController
的方法
onNewResultInternal()
处理数据源获取的结果。

为数据源注册观察者。等待回调的产生。

BaseDataSubscriber
onNewResultImple()
方法的逻辑就简单了,看看数据是否加载完毕和加载的进度情况,如果数据源结果不为空就调用
onNewResultInternal()
方法进一步处理。

看看
onNewResultInternal()
方法做了什么事:

检查是否是自己想要的结果,如果不是,直接释放资源。

如果是想要的数据源,创建对应的drawable。

调用
hierarchy.setImage(draweavke)
设置当前显示的draweable。

调用
getControllerListener().onFilalImageSet()
回调图像设置成功的结果。

最后在finally中释放之前缓存的drawable对象和Image对象。

private void onNewResultInternal(
String id,
DataSource<T> dataSource,
@Nullable T image,
float progress,
boolean isFinished,
boolean wasImmediate) {

// 检查是否是自己想要的结果,如果不是,直接释放资源
....

// 如果是想要的数据源,创建对应的drawable,设置当前显示的drawable,释放之前缓存的drawable对象和Image对象
Drawable drawable = createDrawable(image);
...
try {
// 设置当前显示的drawable
if (isFinished) {
mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate);
// 回调设置图像结束
getControllerListener().onFinalImageSet(id, getImageInfo(image), getAnimatable());
}
...
} finally {
// 释放之前缓存的drawable对象和Image对象
....
}
}


至此,
AbstractDraweeController
类的分析就基本结束。

PipelineDraweeController

为什么选择分析
PipelineDraweeController
?,还记得在Fresco正传(2):DraweeView分析,分析到
Fresco
类源码时调用的
initializeDrawee()
方法么?

private static void initializeDrawee(Context context) {
sDraweeControllerBuilderSupplier = new PipelineDraweeControllerBuilderSupplier(context);
SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);
}


这里表明默认使用的Controller是
PipelineDraweeController


看一下类注释,看看能够了解到什么信息:

DraweeController是ImagePipeline和SettableDraweeHierarchy的桥梁。

实际显示的图像是数据源提供的,而数据源是在
attach
detach
时自动获取和关闭的。

还记得在分析
AbstractDraweeController
时提到过的
getDataSource()
方法吗?这里有实现,看看是怎么样的:

Override
protected DataSource<CloseableReference<CloseableImage>> getDataSource() {
return mDataSourceSupplier.get();
}


先上一张图,清醒清醒,看看
getDataSource()
是怎么样被调用的。



哈哈。我怎么觉得画的特别棒呢。

想要数据源,则需要数据源提供者提供
mDataSourceSupplier
,在
init()
方法中,成员变量
mDataSourceSupplier
被赋值。

private void init(Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier) {
mDataSourceSupplier = dataSourceSupplier;
}


init()
方法在
PipelineDraweeController
的构造方法中调用,在外部传入了
dataSourceSupplier
参数。通过
alt+f7
看看哪里调用构造方法,发现在
PipilineDraweeControllerFactory
工厂中的
newController()
方法,构造了
PipelineDraweeController
类的实例,并将
newController()
dataSourceSupplier
参数传入了构造方法中。

public PipelineDraweeController newController(
Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,
String id,
Object callerContext) {

// 创建控制器
return new PipelineDraweeController(
mResources,
mDeferredReleaser,
mAnimatedDrawableFactory,
mUiThreadExecutor,
dataSourceSupplier,
id,
callerContext);
}


再跟踪一下哪里调用了工厂的
newController()
方法。发现是
PipelineDraweeControllerBuiler
obtainController()
调用了。更深入的细节,例如:
obtainDataSourceSupplier()
先不分析,先把思路捋清楚。

@Override
protected PipelineDraweeController obtainController() {
DraweeController oldController = getOldController();
PipelineDraweeController controller;

// 如果已经有旧的contoller
if (oldController instanceof PipelineDraweeController) {
controller = (PipelineDraweeController) oldController;
controller.initialize(
obtainDataSourceSupplier(),
generateUniqueControllerId(),
getCallerContext());
} else {
// 第一次请求
controller = mPipelineDraweeControllerFactory.newController(
obtainDataSourceSupplier(),
generateUniqueControllerId(),
getCallerContext());
}

// 返回build 所需的controller
return controller;
}


在跟踪一下哪里调用了
obtainController()
方法,发现是在
buildController()
方法中调用的。而又在
AbstractDraweeControllerBuilder
build()
方法中,调用了
buildController()
方法。

protected AbstractDraweeController buildController() {
AbstractDraweeController controller = obtainController(); // 核心,获取controller

//
controller.setRetainImageOnFailure(getRetainImageOnFailure());
maybeBuildAndSetRetryManager(controller);
maybeAttachListeners(controller);
return controller;
}
@Override
public AbstractDraweeController build() {
validate();

// if only a low-res request is specified, treat it as a final request.
if (mImageRequest == null && mMultiImageRequests == null && mLowResImageRequest != null) {
mImageRequest = mLowResImageRequest;
mLowResImageRequest = null;
}

return buildController();
}


最后,是哪里调用的
AbstractDraweeControllerBuilder
build()
方法? 这次你一定很熟悉了,是在
SimpleDraweeView
类的
setImageURI()
方法中。构建出
DraweeController
后,将其交给了
DraweeView
的体系。

public void setImageURI(Uri uri, @Nullable Object callerContext) {

DraweeController controller = mSimpleDraweeControllerBuilder
.setCallerContext(callerContext)
.setUri(uri)
.setOldController(getController())
.build();

setController(controller);
}


最后的问题,
mSimpleDraweeControllerBuiler
是哪里来的?相信不用我多说了吧。

这样整个获取数据源的流程,我们就串联起来了。在看一下这个图,是不是更清晰了?



最后

DraweeController的体系分析就基本完成了,如果觉得对您有帮助,多多留言哦。

下篇分析是如何发出请求的。

github:https://github.com/biezhihua

Fresco正传(3):DraweeHierarchy分析:http://blog.csdn.net/biezhihua/article/details/49800313
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: