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

Fresco 源码分析(一) DraweeView-DraweeHierarchy-DraweeController(MVC) DraweeHierachy+DraweeController的分析的更多相关文章

  1. Fresco 源码分析(一) DraweeView-DraweeHierarchy-DraweeController(MVC) DraweeView的分析

    4. Fresco的内容 为了方便学习,我们先从使用结合官方的文档来分析 4.1 Fresco客户端的使用 在使用Fresco的使用,我们直接使用的是SimpleDraweeView这个类,然后在Ac ...

  2. Fresco 源码分析(二) Fresco客户端与服务端交互(3) 前后台打通

    4.2.1.2.4 PipelineDraweeControllerBuilder.obtainController()源码分析 续 上节中我们提到两个核心的步骤 obtainDataSourceSu ...

  3. Fresco 源码分析 —— 整体架构

    Fresco 是我们项目中图片加载专用框架.虽然我不是负责 Fresco 框架,但是由本人负责组里的图片加载浏览等工作,因此了解 Fresco 的源码有助于我今后的工作,也可以学习 Fresco 的源 ...

  4. Fresco 源码分析(二) Fresco客户端与服务端交互(1) 解决遗留的Q1问题

    4.2 Fresco客户端与服务端的交互(一) 解决Q1问题 从这篇博客开始,我们开始讨论客户端与服务端是如何交互的,这个交互的入口,我们从Q1问题入手(博客按照这样的问题入手,是因为当时我也是从这里 ...

  5. Fresco 源码分析(序)

    1. 为什么要写这个分析的博客 其实关于Fresco的相关内容,大家上网搜索,一般可以找到一大推,但是为什么我还要写关于这个的呢,因为在网上搜索中文和英文的关于fresco的相关知识时,大家只是潜在的 ...

  6. Fresco源码解析 - DataSource怎样存储数据

    Fresco源码解析 - DataSource怎样存储数据 datasource是一个独立的 package,与FB导入的guava包都在同一个工程内 - fbcore. datasource的类关系 ...

  7. Fresco源码解析 - 创建一个ImagePipeline(一)

    在Fresco源码解析 - 初始化过程分析章节中, 我们分析了Fresco的初始化过程,两个initialize方法中都用到了 ImagePipelineFactory类. ImagePipeline ...

  8. dubbo源码解析五 --- 集群容错架构设计与原理分析

    欢迎来我的 Star Followers 后期后继续更新Dubbo别的文章 Dubbo 源码分析系列之一环境搭建 博客园 Dubbo 入门之二 --- 项目结构解析 博客园 Dubbo 源码分析系列之 ...

  9. MVC系列——MVC源码学习:打造自己的MVC框架(四:了解神奇的视图引擎)

    前言:通过之前的三篇介绍,我们基本上完成了从请求发出到路由匹配.再到控制器的激活,再到Action的执行这些个过程.今天还是趁热打铁,将我们的View也来完善下,也让整个系列相对完整,博主不希望烂尾. ...

随机推荐

  1. webkit模块介绍

    一.Webkit模块   用到的第三方库如下:   cairo 一个2D绘图库 casqt Unicode处理用的库,从QT中抽取部分代码形成的 expat 一个XML SAX解析器的库 freety ...

  2. MyEclipse2014中SVN的使用方法

    MyEclipse中的SVN操作手册 1.导入项目 点击工具栏上的[File-Import],进入下图 (如果你的对话框中没有SVN这一条目,可能是因为你没有安装SVN插件,请安装完成后,在看这篇博客 ...

  3. Putty远程登录VMware虚拟机Linux(Ubuntu)

    安装SSH服务 Ubuntu默认并没有安装ssh服务,如果通过ssh链接ubuntu,需要自己手动安装ssh-server.判断是否安装ssh服务,可以通过如下命令进行: www.linuxidc.c ...

  4. c# 闭包 小例

    class Program { static void fnnn() { string[] k = new string[] { "x", "y", " ...

  5. (转)MFC的一些宏的整理 (DECLARE_DYNCREATE/IMPLEMENT_DYNCREATE)

    很早看了MFC的一些宏的实现,什么RUNTIME_CLASS, DECLARE_DYNAMIC, DECLARE_DYNCREATE,IMPLEMENT_DYNCREATE, etc,看了就烦,现在整 ...

  6. HTML常见标签总结

    什么是浏览器 解释和执行HTML源码的工具 五大浏览器:IE.FF(FireFox)(火狐).Chrome(谷歌).Opera(空中).Safari(Apple)(苹果) IE用的是Trident引擎 ...

  7. gcc的-D和-U参数:宏的设置与取消 _CCFLAGS=" -w -enable-threads=posix -DLINUX -D_REENTRANT -DWORKONGN -Dlinux -D_GN_DETAIL_SDR_"

    _CCFLAGS=" -w -enable-threads=posix -DLINUX -D_REENTRANT -DWORKONGN -Dlinux -D_GN_DETAIL_SDR_&q ...

  8. word双面打印的方法

    首先要明白打印的过程 先进入打印机的纸张顶部,肯定是先打印,这样就确定了纸张放置的方向,不会放倒了 肯定是打印在纸张的向上的那一面,这样就确定了打印的正反面 纸张打印的顺序肯定是从上到下,这样就确定了 ...

  9. 10.23lamp环境

    前序: 查考文章:http://www.cnblogs.com/mchina/archive/2012/11/28/2778779.html http://www.centos.bz/2011/09/ ...

  10. 模式串匹配之KMP算法

    模式串匹配之KMP算法 KMP算法 模式值计算(next[j]) (1) next[0]=-1,  第一个字符模式值为-1 (2) next[j]=-1, T中下标为j的字符与首字符相同,且j前面的1 ...