Fresco 源码分析(一) DraweeView-DraweeHierarchy-DraweeController(MVC) DraweeHierachy+DraweeController的分析

4.1.5.2 模型层DraweeHierachy继承体系以及各个类的作用

DraweeHierachy (I)
--| SettableDraweeHierarchy (I)
------| GenericDraweeHierarchy

DraweeHierachy:

  1. 用于获取顶层的drawable
    SettableDraweeHierachy:
  2. 图像可以被重置
  3. 图像可以设置进度
  4. 设置失败
  5. 设置重试
  6. 设置controllerOverlay

在理解获取顶层的Drawable时,需要首先理解Drawable的继承结构

先来看看DraweeHierachy的源码,发现其为接口,并且只有一个方法,就是用于获取顶层的Drawable

DraweeHierachy的源码

public interface DraweeHierarchy {

  /**
   * Returns the top level drawable in the corresponding hierarchy. Hierarchy should always have
   * the same instance of its top level drawable.
   * @return top level drawable
   */
  public Drawable getTopLevelDrawable();
}

再来看看继承其的接口,SettableDraweeHierachy,如上所述

  1. 图像可以被重置

  2. 图像可以设置进度

  3. 设置失败

  4. 设置重试

  5. 设置controllerOverlay

     public interface SettableDraweeHierarchy extends DraweeHierarchy {
       public void reset();
       public void setImage(Drawable drawable, float progress, boolean immediate);
       public void setProgress(float progress, boolean immediate);
       public void setFailure(Throwable throwable);
       public void setRetry(Throwable throwable);
       public void setControllerOverlay(Drawable drawable);
     }
    

4.1.5.3 控制层DraweeController继承体系以及个各类的作用

DraweeController
--| AbstractDraweeController
----| PipelineDraweeController

DraweeController:

  1. 获取和设置Hieraychy
  2. view的各种事件通知过来,controller来控制这些逻辑的操作(onAttach/onDetach/onTouchEvent/getAnimatable)

AbstractDraweeController:

  1. 最关键的功能: 实现了客户端向服务端的提交请求,即向DataSource中注册观察者,在有结果返回的时候,在主线程通知客户端更新即可,即设置Hierarychy的drawable即可

  2. 参照之前的分析方式,仍然采用先构造,然后具体方法的顺序
    2.1 构造方法,设置了UI线程池,重试,以及手势相关的信息

    public AbstractDraweeController(
    DeferredReleaser deferredReleaser,
    Executor uiThreadImmediateExecutor,
    String id,
    Object callerContext) {
    mDeferredReleaser = deferredReleaser;
    mUiThreadImmediateExecutor = uiThreadImmediateExecutor;
    init(id, callerContext);
    }

    /**
    * Initializes this controller with the new id and caller context.
    * This allows for reusing of the existing controller instead of instantiating a new one.
    * This method should be called when the controller is in detached state.
    * @param id unique id for this controller
    * @param callerContext tag and context for this controller
    */
    protected void initialize(String id, Object callerContext) {
    init(id, callerContext);
    }

    private void init(String id, Object callerContext) {
    mEventTracker.recordEvent(Event.ON_INIT_CONTROLLER);
    // cancel deferred release
    if (mDeferredReleaser != null) {
    mDeferredReleaser.cancelDeferredRelease(this);
    }
    // reinitialize mutable state (fetch state)
    mIsAttached = false;
    releaseFetch();
    // reinitialize optional components
    if (mRetryManager != null) {
    mRetryManager.init();
    }
    if (mGestureDetector != null) {
    mGestureDetector.init();
    mGestureDetector.setClickListener(this);
    }
    if (mControllerListener instanceof InternalForwardingListener) {
    ((InternalForwardingListener) mControllerListener).clearListeners();
    } else {
    mControllerListener = null;
    }
    // clear hierarchy and controller overlay
    if (mSettableDraweeHierarchy != null) {
    mSettableDraweeHierarchy.reset();
    mSettableDraweeHierarchy.setControllerOverlay(null);
    mSettableDraweeHierarchy = null;
    }
    mControllerOverlay = null;
    // reinitialize constant state
    if (FLog.isLoggable(FLog.VERBOSE)) {
    FLog.v(TAG, "controller %x %s -> %s: initialize", System.identityHashCode(this), mId, id);
    }
    mId = id;
    mCallerContext = callerContext;
    }

    2.2 具体方法,在这里做分析时,我们重点关注图片如何获取,因而我们关注的核心方法是onAttach(),在这里实现了图片请求的机制,以及图片获取到如何回调,如何显示到UI层的控制,在下面的程序中,看到核心的设置的方法是submitRequest()

    @Override
    public void onAttach() {
    // 记录log
    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();
    }
    }

此处以第一次请求为例,这样分析比较简单,查看下面的方法,在请求时,设置请求的进度为0,获取到数据源(DataSource),然后给数据源注册观察者(DataSubscriber),先查看下面的SubmitRequest方法

protected void submitRequest() {
    mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT);
    getControllerListener().onSubmit(mId, mCallerContext);
    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;
	//------------此处以第一次请求为例,所以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);
  }

到了这里,一次请求已经完成了,请求的结果会在回调中执行,但是请求是如何生成的呢?我们并没有看到具体发送请求的逻辑,这个疑问我们先记录下来(暂且标记为Q1)。先来看看对于请求结果是如何处理的,以新的一次请求结果为例,onNewResultImpl()方法,而onNewResultImpl方法,以image不为空为例,最终会调用AbstractDraweeController.onNewResultInternal()方法。下面我们来看看,是如何处理这次新的请求的结果。

  1. 判断是否是想要的数据源,即查看数据信息是否是当前请求的信息,如果不是,直接释放了资源

  2. 如果是想要的数据源,创建对应的drawable,设置当前显示的drawable,释放之前缓存的drawable对象和Image对象

    private void onNewResultInternal(
    String id,
    DataSource dataSource,
    @Nullable T image,
    float progress,
    boolean isFinished,
    boolean wasImmediate) {
    // ignore late callbacks (data source that returned the new result is not the one we expected)
    if (!isExpectedDataSource(id, dataSource)) {
    logMessageAndImage("ignore_old_datasource @ onNewResult", image);
    releaseImage(image);
    dataSource.close();
    return;
    }
    mEventTracker.recordEvent(
    isFinished ? Event.ON_DATASOURCE_RESULT : Event.ON_DATASOURCE_RESULT_INT);
    // create drawable
    Drawable drawable;
    try {
    drawable = createDrawable(image);
    } catch (Exception exception) {
    logMessageAndImage("drawable_failed @ onNewResult", image);
    releaseImage(image);
    onFailureInternal(id, dataSource, exception, isFinished);
    return;
    }
    T previousImage = mFetchedImage;
    Drawable previousDrawable = mDrawable;
    mFetchedImage = image;
    mDrawable = drawable;
    try {
    // set the new image
    if (isFinished) {
    logMessageAndImage("set_final_result @ onNewResult", image);
    mDataSource = null;
    mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate);
    getControllerListener().onFinalImageSet(id, getImageInfo(image), getAnimatable());
    // IMPORTANT: do not execute any instance-specific code after this point
    } else {
    logMessageAndImage("set_intermediate_result @ onNewResult", image);
    mSettableDraweeHierarchy.setImage(drawable, progress, wasImmediate);
    getControllerListener().onIntermediateImageSet(id, getImageInfo(image));
    // IMPORTANT: do not execute any instance-specific code after this point
    }
    } finally {
    if (previousDrawable != null && previousDrawable != drawable) {
    releaseDrawable(previousDrawable);
    }
    if (previousImage != null && previousImage != image) {
    logMessageAndImage("release_previous_result @ onNewResult", previousImage);
    releaseImage(previousImage);
    }
    }
    }

好了,就是获取到图像后续的操作,这个其实就是我们UI的操作,分析到此即可,其他的情况,我们参照这个分析的方式分析即可。下面我们来解决一下之前的Q1问题,数据源的请求是如何发送出去的,这个问题就比较复杂了,我们需要通过至少四篇的博客来分析这个请求的过程。
下篇博客:Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题 :http://www.cnblogs.com/pandapan/p/4646786.html

安卓源码分析群: Android源码分析QQ1群号:164812238

posted @ 2015-07-13 23:02  Panda Pan  阅读(1567)  评论(0编辑  收藏  举报