• 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

  • 相关阅读:
    整理了8个Python中既冷门又实用的技巧
    python中68个内置函数的总结
    Python中常见的8种数据结构的实现方法(建议收藏)
    python基础教程:dir()和__dict__属性的区别
    Python 优雅获取本机 IP 方法
    Python类中的self到底是干啥的
    python中反转列表的三种方式
    Flask学习笔记(2)-login_page
    利用Flask + python3.6+MYSQL编写一个简单的评论模块。
    最近写了个自动填写调查的问卷的简单爬虫
  • 原文地址:https://www.cnblogs.com/pandapan/p/4634563.html
Copyright © 2020-2023  润新知