第一篇 Fresco初始化流程
第二篇 DraweeView, DraweeHierarchy 分析
DraweeController
根据之前的分析,调用SimpleDraweeView.setImageURI()方法就可以显示图片,源码很简单:
public void setImageURI(Uri uri, @Nullable Object callerContext) {
DraweeController controller = mSimpleDraweeControllerBuilder
.setCallerContext(callerContext)
.setUri(uri)
.setOldController(getController())
.build();
setController(controller);
}
Fresco源码使用MVC架构,Controller在MVC中主要处理逻辑。在setImageURI方法中new了一个Controller实例,然后setContoller图片就可以显示了,所有的逻辑都交给Controller处理了。
public class DraweeView<DH extends DraweeHierarchy> extends ImageView {
private DraweeHolder<DH> mDraweeHolder;
private void init(Context context) {
mDraweeHolder = DraweeHolder.create(null, context);
}
public void setController(@Nullable DraweeController draweeController) {
mDraweeHolder.setController(draweeController);
super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());
}
}
SimpleDraweeView 的setController方法定义在DraweeView中,将得到的Controller的对象传到DraweeHolder中,上一篇分析在DraweeView初始化时实例化了DraweeHierarchy对象,然后调用setHierarchy()方法也传到了DraweeHolder中。此时DraweeHolder就有了Controller和DraweeHierarchy的引用,而DraweeHolder又是在DraweeView中创建,这样DraweeView就通过直接引用DraweeHolder间接引用了Controller,和DraweeHiearchy。(标准的解耦)。
DraweeHolder调用了Controller的onAttach,下面的操作进到了DraweeController中:
private void attachController() {
if (mIsControllerAttached) {
return;
}
mEventTracker.recordEvent(Event.ON_ATTACH_CONTROLLER);
mIsControllerAttached = true;
if (mController != null &&
mController.getHierarchy() != null) {
mController.onAttach();
}
}
DraweeController是一个接口,继承关系如下:
根据继承关系,AbstractDraweeController中实现了onAttach方法:
@Override
public void onAttach() {
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(
TAG,
"controller %x %s: onAttach: %s",
System.identityHashCode(this),
mId,
mIsRequestSubmitted ? "request already submitted" : "request needs submit");
}
mEventTracker.recordEvent(Event.ON_ATTACH_CONTROLLER);
Preconditions.checkNotNull(mSettableDraweeHierarchy);
mDeferredReleaser.cancelDeferredRelease(this);
mIsAttached = true;
if (!mIsRequestSubmitted) {
submitRequest();
}
}
protected void submitRequest() {
mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT);
getControllerListener().onSubmit(mId, mCallerContext);
//设置进度为0 开始设置图片了
mSettableDraweeHierarchy.setProgress(0, true);
mIsRequestSubmitted = true;
mHasFetchFailed = false;
//得到数据源
mDataSource = getDataSource();
if (FLog.isLoggable(FLog.VERBOSE)) {
FLog.v(
TAG,
"controller %x %s: submitRequest: dataSource: %x",
System.identityHashCode(this),
mId,
System.identityHashCode(mDataSource));
}
final String id = mId;
final boolean wasImmediate = mDataSource.hasResult();
//创建观察者
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();
T image = dataSource.getResult();
if (image != null) {
onNewResultInternal(id, dataSource, image, 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);
}
};
//绑定观察者
mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor);
}
调用submitRequest()提交了请求。(使用了RxJava中的观察者模式,注册观察者,DataSource内容发生变化,会回调到dataSubscriber中)。
getDataSource()定义在PipelineDraweeController中,代码很简单,从mDataSourceSupplier中取出DataSource。 而mDataSourceSupplier是创建Controller时通过构造方法传进来的,所以得知道Controller是咋创建的。
@Override
protected DataSource<CloseableReference<CloseableImage>> getDataSource() {
return mDataSourceSupplier.get();
}
Controller创建比较复杂,从网上借鉴了一张流程图(原文链接)
public void setImageURI(Uri uri, @Nullable Object callerContext) {
DraweeController controller = mSimpleDraweeControllerBuilder
.setCallerContext(callerContext)
.setUri(uri)
.setOldController(getController())
.build();
setController(controller);
}
Supplier的创建主要分下面几步:
1、mSimpleDraweeControllerBuilder是Controller的构建者,调用setUri(uri)时将Uri封装成ImageRequest然后调用super将ImageRequest保存到了AbstractDraweeControllerBuilder中。
@Override
public PipelineDraweeControllerBuilder setUri(Uri uri) {
return super.setImageRequest(ImageRequest.fromUri(uri));
}
2、在AbstractDraweeControllerBuilder中定义obtainDataSourceSupplier()方法将第一步通过setUri传入的ImageRequest转换成Supplier。
3、SuppliermPipelineDraweeControllerFactory.newController创建一个Controller,把Supplier传到了Controller中。
执行完这三步,当SimpleDraweeView调用setController时,通过Supplier.get()可得到DataSource了。
PS:从上面流程中看到实例化一个Controller,直接或间接调用了四个类,让人看着很蛋疼,Fresco这样写肯定也有他的道理。
之前分析类继承关系时,看到Fresco中不只有一个PipelineDraweeController,还有VolleyDraweeController(将来可能还有更多),这两个Controller都继承AbstractDraweeController。其中AbstractDraweeControllerBuilder的功能是构建一个Controller,build功能是所有的Builder中必备的功能,所以build方法定义在了AbstractDraweeControllerBuilder中。但是Controller有很多种,所以具体构建 Controller的功能交给了各自的继承类,例如通过PipelineDraweeControllerBuilder构建出来PipelineDraweeController。在Builder中再调用各自Controller的工厂类来最终得到一个Controller。
虽然让看代码的很蛋疼,但是代码的层次更清楚,可扩展性也更高,值得借鉴。
到此Controller的分析也就完成了,下次将分析Fresco的网络请求。