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

4. Fresco的内容

为了方便学习,我们先从使用结合官方的文档来分析

4.1 Fresco客户端的使用##

在使用Fresco的使用,我们直接使用的是SimpleDraweeView这个类,然后在Activity或者Fragment中使用findViewById,然后便调用SimpleDraweeView.setImageUri(),这个方法,便直接可以加载图片,那么在这之间到底是怎么做的呢?结果打开SimpleDraweeView这个类,发现其继承体系,又发现中间有其他一些类,如果只是硬着头皮看代码,我们也会发现其中的逻辑,但是通过官方文档的介绍,我们会降低分析的时间花销
官方关于SimpleDraweeView的介绍

4.1.1 Drawees

rawees 负责图片的呈现,包含几个组件,有点像MVC模式

4.1.2 DraweeView(Viewer)

继承于 View, 负责图片的显示。

4.1.3 DraweeHierarchy(Model)

DraweeHierarchy 用于组织和维护最终绘制和呈现的Drawable对象,相当于MVC中的M。

4.1.4 DraweeController(Controller)

DraweeController 负责和 image loader 交互(默认是Fresco中 image pipeline),可以创建一个这个类的实例,来实现对所要显示的图片做更多的控制

4.1.5 DraweeView(Viewer)-DraweeHierarchy(Model)-DraweeController(Controller)的代码体现

了解通用的MVC模式,便知道Model负责的是持有数据,Viewer用于展示数据,Controller用于控制数据的逻辑,即核心的控制逻辑位于Controller中
MVC的示意图:

这个只是通用的MVC示意图,那么在Drawees中是如何体现呢:

在查看三者的关系时,我们从Viewer入手,在查看SimpleDraweeView,先看其继承体系

4.1.5.1 视图层DraweeView继承体系及各个类的作用

DraweeView
--| GenericDraweeView
------| SimpleDraweeView

DraweeView (Viewer)
获取和设置Hierarchy+Controller,DraweeView的相关信息在DraweeHolder中
DraweeHolder是一个辅助的类,解耦的设计方式,将需要设置以及传递控制的信息,全部交给DrawHolder来实现

GenericDraweeView
解析在xml中设置的属性

SimpleDraweeView

  1. 从外界设置ConrolllerBuilderSupplier
  2. 可以设置ImageUri

核心的业务逻辑位于DraweeView中
在控件初始化时,初始化了一个DraweeHolder

DraweeView的初始化源码

  private DraweeHolder<DH> mDraweeHolder;

  public DraweeView(Context context) {
    super(context);
    init(context);
  }

  public DraweeView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(context);
  }

  public DraweeView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(context);
  }

  //---init中创建了一个DraweeHolder
  private void init(Context context) {
    mDraweeHolder = DraweeHolder.create(null, context);
  }

再查看剩余的DraweeView的程序,发现其均将只是将相关事件传递给DraweeHolder,这是一种解耦的设计方式,以后就是不采用DraweeView,采用其他的方式,照样可以使用这套逻辑

DraweeView的剩余源码
查看完DraweeView的源码后,再查看其子类的源码,刚才已经提到,GenericDraweeView解析在xml中设置的属性

  public void setHierarchy(DH hierarchy) {
    mDraweeHolder.setHierarchy(hierarchy);
    super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());
  }

  public DH getHierarchy() {
    return mDraweeHolder.getHierarchy();
  }

  public boolean hasHierarchy() {
    return mDraweeHolder.hasHierarchy();
  }

  @Nullable public Drawable getTopLevelDrawable() {
    return mDraweeHolder.getTopLevelDrawable();
  }

  public void setController(@Nullable DraweeController draweeController) {
    mDraweeHolder.setController(draweeController);
    super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());
  }

  @Nullable public DraweeController getController() {
    return mDraweeHolder.getController();
  }

  public boolean hasController() {
    return mDraweeHolder.getController() != null;
  }

  @Override
  protected void onAttachedToWindow() {
    super.onAttachedToWindow();
    mDraweeHolder.onAttach();
  }

  @Override
  protected void onDetachedFromWindow() {
    super.onDetachedFromWindow();
    mDraweeHolder.onDetach();
  }

  @Override
  public void onStartTemporaryDetach() {
    super.onStartTemporaryDetach();
    mDraweeHolder.onDetach();
  }

  @Override
  public void onFinishTemporaryDetach() {
    super.onFinishTemporaryDetach();
    mDraweeHolder.onAttach();
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (mDraweeHolder.onTouchEvent(event)) {
      return true;
    }
    return super.onTouchEvent(event);
  }


  @Override
  @Deprecated
  public void setImageDrawable(Drawable drawable) {
    mDraweeHolder.setController(null);
    super.setImageDrawable(drawable);
  }

  @Override
  @Deprecated
  public void setImageBitmap(Bitmap bm) {
    mDraweeHolder.setController(null);
    super.setImageBitmap(bm);
  }

  @Override
  @Deprecated
  public void setImageResource(int resId) {
    mDraweeHolder.setController(null);
    super.setImageResource(resId);
  }

  @Override
  @Deprecated
  public void setImageURI(Uri uri) {
    mDraweeHolder.setController(null);
    super.setImageURI(uri);
  }

GenericDraweeView构造的源码
构造的源码,分为两种,一种是从外界直接设置GenericDraweeHierarchy,另外一种是普通的xml中直接生成的GenericDraweeView,其实都是在自身设置了一个hierarchy,设置给了DraweeHolder,并且直接设置自身显示的view,获取的是DraweeHolder的topDrawable,这个DraweeHolder的getTopDrawable(),其实还是获取的GenericDraweeHierarchy的getTopDrawable()

public class GenericDraweeView extends DraweeView<GenericDraweeHierarchy> {

  private float mAspectRatio = 0;
  private final AspectRatioMeasure.Spec mMeasureSpec = new AspectRatioMeasure.Spec();

  public GenericDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
    super(context);
    setHierarchy(hierarchy);
  }

  public GenericDraweeView(Context context) {
    super(context);
    inflateHierarchy(context, null);
  }

  public GenericDraweeView(Context context, AttributeSet attrs) {
    super(context, attrs);
    inflateHierarchy(context, attrs);
  }

  public GenericDraweeView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    inflateHierarchy(context, attrs);
  }
}

inflateHierarchy()的源码
在inflater的过程中,使用了构造者模式,构造者模式,一般适用于类的属性比较多,并且需要链式书写,在安卓的使用中,AlertDialog中也是使用了构造者模式,虽然模式很好用,但是写起来比较费劲,因为感觉好多东西感觉都是重复的

 private void inflateHierarchy(Context context, @Nullable AttributeSet attrs) {
	......
    int fadeDuration = GenericDraweeHierarchyBuilder.DEFAULT_FADE_DURATION;
    // images & scale types defaults
    int placeholderId = 0;
	......	
    if (attrs != null) {
      TypedArray gdhAttrs = context.obtainStyledAttributes(
          attrs,
          R.styleable.GenericDraweeView);
      try {
        // fade duration
        fadeDuration = gdhAttrs.getInt(
            R.styleable.GenericDraweeView_fadeDuration,
            fadeDuration);
		//----解析xml中设置的各个属性
		.......
      }
      finally {
        gdhAttrs.recycle();
      }
    }

    GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(resources);
    // set fade duration
    builder.setFadeDuration(fadeDuration);
    // set images & scale types
    if (placeholderId > 0) {
      builder.setPlaceholderImage(resources.getDrawable(placeholderId), placeholderScaleType);
    }
	//---将解析出来的xml属性,设置给builder中的相关属性
	......
    setHierarchy(builder.build());
  }

SimpleDraweeView的源码分析
分析方式同上,先查看构造函数,然后看其他方法,
构造方法方法,同样是两种方法,一种是支持从类中直接创建的,另外一种是从xml中创建出来的,在这两种方式中,都是先调用的父类的构造方法,然后在init中初始化了一个SimpleDraweeControllerBuilder

  private SimpleDraweeControllerBuilder mSimpleDraweeControllerBuilder;

  public SimpleDraweeView(Context context, GenericDraweeHierarchy hierarchy) {
    super(context, hierarchy);
    init();
  }

  public SimpleDraweeView(Context context) {
    super(context);
    init();
  }

  public SimpleDraweeView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
  }

  public SimpleDraweeView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init();
  }

  private void init() {
    if (isInEditMode()) {
      return;
    }
    Preconditions.checkNotNull(
        sDraweeControllerBuilderSupplier,
        "SimpleDraweeView was not initialized!");
    mSimpleDraweeControllerBuilder = sDraweeControllerBuilderSupplier.get();
  }

在init方法中,用到了一个Preconditions.checkNotNull的方法(这个是google自己提供的java的扩展包,这个包建议大家还是到网上查找相关介绍,因为功能比较强大。),另外,既然在这里都已经判空,那么sDraweeControllerBuilderSupplier肯定是要提前初始化的,在类中查看初始化的位置,发现位于静态的初始化方法中,至于何时调用这个方法,提前告诉大家,是在我们写Fresco.init()的方法,便已经初始化好了的,这就是为什么我们可以轻松的使用这个SimpleDraweeView了
private static Supplier<? extends SimpleDraweeControllerBuilder> sDraweeControllerBuilderSupplier;

  /** Initializes {@link SimpleDraweeView} with supplier of Drawee controller builders. */
  public static void initialize(
      Supplier<? extends SimpleDraweeControllerBuilder> draweeControllerBuilderSupplier) {
    sDraweeControllerBuilderSupplier = draweeControllerBuilderSupplier;
  }

SimpleDraweeView的面向用户方法的分析
这个是面向UI层开放的接口setImageUri(),下面我们查看其源码,发现其构造了一个DraweeController,然后设置给了SimpleDraweeView而已,同样,这里使用的是构造者模式
/**
* Displays an image given by the uri.
*
* @param uri uri of the image
* @param callerContext caller context
*/
public void setImageURI(Uri uri, @Nullable Object callerContext) {
DraweeController controller = mSimpleDraweeControllerBuilder
.setCallerContext(callerContext)
.setUri(uri)
.setOldController(getController())
.build();
setController(controller);
}

下篇我们要分析DraweeHierachy和DraweeController 链接地址:(http://www.cnblogs.com/pandapan/p/4644195.html)

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

posted @ 2015-07-09 23:48  Panda Pan  阅读(4393)  评论(0编辑  收藏  举报