27
2017
09

Fresco解析 (Controller)

第一篇 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的网络请求。

上一篇:Android上的依赖库简介 下一篇:Android调用系统邮件发送附件 文件大小0B