Fresco解析 (Controller)

来源:互联网 发布:上海英翼传媒 知乎 编辑:程序博客网 时间:2024/05/22 15:09

第一篇 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是一个接口,继承关系如下:
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的网络请求。