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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM