Fresco SimpleDraweeView界面源碼分析

Fresco 網(wǎng)絡(luò)請求在前面2篇介紹完了圆仔,我們來看看Fresco Hierarchy(view分層結(jié)構(gòu))

/**
 * This view takes a uri as input and internally builds and sets a controller.
 *
 * <p>This class must be statically initialized in order to be used. If you are using the Fresco
 * image pipeline, use {@link com.facebook.drawee.backends.pipeline.Fresco#initialize} to do this.
 */
public class SimpleDraweeView extends GenericDraweeView {

  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;
  }

  /** Shuts {@link SimpleDraweeView} down. */
  public static void shutDown() {
    sDraweeControllerBuilderSupplier = null;
  }

  private SimpleDraweeControllerBuilder mSimpleDraweeControllerBuilder;

   ......

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public SimpleDraweeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    init(context, attrs);
  }

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

    if (attrs != null) {
      TypedArray gdhAttrs = context.obtainStyledAttributes(
          attrs,
          R.styleable.SimpleDraweeView);
      try {
        if (gdhAttrs.hasValue(R.styleable.SimpleDraweeView_actualImageUri)) {
          setImageURI(Uri.parse(gdhAttrs.getString(R.styleable.SimpleDraweeView_actualImageUri)), null);
        }
      } finally {
        gdhAttrs.recycle();
      }
    }
  }

    ......

  /**
   * 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);
  }
}

這個(gè)類用于你界面布局垃瞧,父類是imageview,他會自己創(chuàng)建DraweeController和自身綁定坪郭,關(guān)于Supplier是外部提供關(guān)于下載和維護(hù)个从,Cache提供的工廠類,在Frescoc:init()時(shí)候創(chuàng)建歪沃。
SimpleDraweeView用法:

Paste_Image.png

SimpleDraweeView詳細(xì)用法

感覺還是少了很多東西嗦锐,接著我們看下基類:

/**
 * DraweeView that uses GenericDraweeHierarchy.
 *
 * The hierarchy can be set either programmatically or inflated from XML.
 * See {@link GenericDraweeHierarchyInflater} for supported XML attributes.
 */
public class GenericDraweeView extends DraweeView<GenericDraweeHierarchy> {

  .......

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

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public GenericDraweeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    inflateHierarchy(context, attrs);
  }

  protected void inflateHierarchy(Context context, @Nullable AttributeSet attrs) {
    GenericDraweeHierarchyBuilder builder =
        GenericDraweeHierarchyInflater.inflateBuilder(context, attrs);
    setAspectRatio(builder.getDesiredAspectRatio());
    setHierarchy(builder.build());
  }
}

GenericDraweeView 說明是可支持可編程和支持xml布局屬性寫法的,最后它會初始化一個(gè)Hierarchy
來看看GenericDraweeHierarchyBuilder和GenericDraweeHierarchyInflater干了啥
GenericDraweeHierarchyBuilder:

/**
 * Class to construct a {@link GenericDraweeHierarchy}.
 *
 * <p/> Drawables must not be reused by multiple hierarchies. Each hierarchy needs to have its own
 * drawable instances. Since this builder does not do deep copies of the input parameters, it is
 * the caller's responsibility to pass a different drawable instances for each hierarchy built.
 * Likewise, hierarchies must not be reused by multiple views. Each view needs to have its own
 * instance of a hierarchy. The caller is responsible for building a new hierarchy for each view.
 */
public class GenericDraweeHierarchyBuilder {

  public static final int DEFAULT_FADE_DURATION = 300;
  public static final ScaleType DEFAULT_SCALE_TYPE = ScaleType.CENTER_INSIDE;
  public static final ScaleType DEFAULT_ACTUAL_IMAGE_SCALE_TYPE = ScaleType.CENTER_CROP;

  private Resources mResources;

  private int mFadeDuration;

  private float mDesiredAspectRatio;

  private Drawable mPlaceholderImage;
  private @Nullable ScaleType mPlaceholderImageScaleType;

  private Drawable mRetryImage;
  private ScaleType mRetryImageScaleType;

  private Drawable mFailureImage;
  private ScaleType mFailureImageScaleType;

  private Drawable mProgressBarImage;
  private ScaleType mProgressBarImageScaleType;

  private ScaleType mActualImageScaleType;
  private Matrix mActualImageMatrix;
  private PointF mActualImageFocusPoint;
  private ColorFilter mActualImageColorFilter;

  private Drawable mBackground;
  private List<Drawable> mOverlays;
  private Drawable mPressedStateOverlay;

  private RoundingParams mRoundingParams;

  public GenericDraweeHierarchyBuilder(Resources resources) {
    mResources = resources;
    init();
  }

  /**
   * Initializes this builder to its defaults.
   */
  private void init() {
    mFadeDuration = DEFAULT_FADE_DURATION;

    mDesiredAspectRatio = 0;

    mPlaceholderImage = null;
    mPlaceholderImageScaleType = DEFAULT_SCALE_TYPE;

    mRetryImage = null;
    mRetryImageScaleType = DEFAULT_SCALE_TYPE;

    mFailureImage = null;
    mFailureImageScaleType = DEFAULT_SCALE_TYPE;

    mProgressBarImage = null;
    mProgressBarImageScaleType = DEFAULT_SCALE_TYPE;

    mActualImageScaleType = DEFAULT_ACTUAL_IMAGE_SCALE_TYPE;
    mActualImageMatrix = null;
    mActualImageFocusPoint = null;
    mActualImageColorFilter = null;

    mBackground = null;
    mOverlays = null;
    mPressedStateOverlay = null;

    mRoundingParams = null;
  }

  /**
   * Sets a background.
   *
   * @param background background drawable
   * @return modified instance of this builder
   */
  public GenericDraweeHierarchyBuilder setBackground(@Nullable Drawable background) {
    mBackground = background;
    return this;
  }

  private void validate() {
    if (mOverlays != null) {
      for (Drawable overlay : mOverlays) {
        Preconditions.checkNotNull(overlay);
      }
    }
  }

  /**
   * Builds the hierarchy.
   */
  public GenericDraweeHierarchy build() {
    validate();
    return new GenericDraweeHierarchy(this);
  }
}

這個(gè)類一看就是builder模式沪曙,一堆set和get方法與GenericDraweeHierarchy綁定
GenericDraweeHierarchyInflater:

/**
 * Inflater for the {@code GenericDraweeHierarchy}.
 * 解析AttributeSet
 */
public class GenericDraweeHierarchyInflater {

  /**
   * Inflates a new hierarchy builder from XML.
   * The builder can then be modified in order to override XML attributes if necessary.
   */
  public static GenericDraweeHierarchyBuilder inflateBuilder(
      Context context,
      @Nullable AttributeSet attrs) {
    Resources resources = context.getResources();
    GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(resources);
    return updateBuilder(builder, context, attrs);
  }

  /**
   * Updates the existing hierarchy builder based on the XML attributes.
   *
   * This method is useful if a custom view uses different default values. In that case a
   * builder with adjusted default values can be passed to this method and only the properties
   * explicitly specified in XML will be overridden.
   * The builder can be modified afterwards in case some XML attributes needs to be overridden.
   *
   * @param builder a hierarchy builder to be updated
   * @return the modified instance of the same builder
   */
  public static GenericDraweeHierarchyBuilder updateBuilder(
      GenericDraweeHierarchyBuilder builder,
      Context context,
      @Nullable AttributeSet attrs) {
    // these paramters cannot be applied immediately so we store them first
    int progressBarAutoRotateInterval = 0;
    int roundedCornerRadius = 0;
    boolean roundTopLeft = true;
    boolean roundTopRight = true;
    boolean roundBottomLeft = true;
    boolean roundBottomRight = true;

    if (attrs != null) {
      TypedArray gdhAttrs = context.obtainStyledAttributes(
        attrs,
        R.styleable.GenericDraweeHierarchy);
      try {
        final int indexCount = gdhAttrs.getIndexCount();
        for (int i = 0; i < indexCount; i++) {
          final int attr = gdhAttrs.getIndex(i);
          // most popular ones first
          if (attr == R.styleable.GenericDraweeHierarchy_actualImageScaleType) {
            builder.setActualImageScaleType(getScaleTypeFromXml(gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_placeholderImage) {
            builder.setPlaceholderImage(getDrawable(context, gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_pressedStateOverlayImage) {
            builder.setPressedStateOverlay(getDrawable(context, gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_progressBarImage) {
            builder.setProgressBarImage(getDrawable(context, gdhAttrs, attr));

          // the remaining ones without any particular order
          } else if (attr == R.styleable.GenericDraweeHierarchy_fadeDuration) {
            builder.setFadeDuration(gdhAttrs.getInt(attr, 0));

          } else if (attr == R.styleable.GenericDraweeHierarchy_viewAspectRatio) {
            builder.setDesiredAspectRatio(gdhAttrs.getFloat(attr, 0));

          } else if (attr == R.styleable.GenericDraweeHierarchy_placeholderImageScaleType) {
            builder.setPlaceholderImageScaleType(getScaleTypeFromXml(gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_retryImage) {
            builder.setRetryImage(getDrawable(context, gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_retryImageScaleType) {
            builder.setRetryImageScaleType(getScaleTypeFromXml(gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_failureImage) {
            builder.setFailureImage(getDrawable(context, gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_failureImageScaleType) {
            builder.setFailureImageScaleType(getScaleTypeFromXml(gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_progressBarImageScaleType) {
            builder.setProgressBarImageScaleType(getScaleTypeFromXml(gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_progressBarAutoRotateInterval) {
            progressBarAutoRotateInterval =
                gdhAttrs.getInteger(attr, progressBarAutoRotateInterval);

          } else if (attr == R.styleable.GenericDraweeHierarchy_backgroundImage) {
            builder.setBackground(getDrawable(context, gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_overlayImage) {
            builder.setOverlay(getDrawable(context, gdhAttrs, attr));

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundAsCircle) {
            getRoundingParams(builder).setRoundAsCircle(gdhAttrs.getBoolean(attr, false));

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundedCornerRadius) {
            roundedCornerRadius = gdhAttrs.getDimensionPixelSize(attr, roundedCornerRadius);

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundTopLeft) {
            roundTopLeft = gdhAttrs.getBoolean(attr, roundTopLeft);

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundTopRight) {
            roundTopRight = gdhAttrs.getBoolean(attr, roundTopRight);

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundBottomLeft) {
            roundBottomLeft = gdhAttrs.getBoolean(attr, roundBottomLeft);

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundBottomRight) {
            roundBottomRight = gdhAttrs.getBoolean(attr, roundBottomRight);

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundWithOverlayColor) {
            getRoundingParams(builder).setOverlayColor(gdhAttrs.getColor(attr, 0));

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundingBorderWidth) {
            getRoundingParams(builder).setBorderWidth(gdhAttrs.getDimensionPixelSize(attr, 0));

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundingBorderColor) {
            getRoundingParams(builder).setBorderColor(gdhAttrs.getColor(attr, 0));

          } else if (attr == R.styleable.GenericDraweeHierarchy_roundingBorderPadding) {
            getRoundingParams(builder).setPadding(gdhAttrs.getDimensionPixelSize(attr, 0));

          }
        }
      } finally {
        gdhAttrs.recycle();
      }
    }

    // wrap progress bar if auto-rotating requested
    if (builder.getProgressBarImage() != null && progressBarAutoRotateInterval > 0) {
      builder.setProgressBarImage(
        new AutoRotateDrawable(builder.getProgressBarImage(), progressBarAutoRotateInterval));
    }

    // set rounded corner radii if requested
    if (roundedCornerRadius > 0) {
      getRoundingParams(builder).setCornersRadii(
        roundTopLeft ? roundedCornerRadius : 0,
        roundTopRight ? roundedCornerRadius : 0,
        roundBottomRight ? roundedCornerRadius : 0,
        roundBottomLeft ? roundedCornerRadius : 0);
    }
    
    return builder;
  }

  .......

  /**
   * Returns the scale type indicated in XML, or null if the special 'none' value was found.
   * Important: these values need to be in sync with GenericDraweeHierarchy styleable attributes.
   */
  @Nullable
  private static ScaleType getScaleTypeFromXml(
      TypedArray gdhAttrs,
      int attrId) {
    switch (gdhAttrs.getInt(attrId, -2)) {
      case -1: // none
        return null;
      case 0: // fitXY
        return ScaleType.FIT_XY;
      case 1: // fitStart
        return ScaleType.FIT_START;
      case 2: // fitCenter
        return ScaleType.FIT_CENTER;
      case 3: // fitEnd
        return ScaleType.FIT_END;
      case 4: // center
        return ScaleType.CENTER;
      case 5: // centerInside
        return ScaleType.CENTER_INSIDE;
      case 6: // centerCrop
        return ScaleType.CENTER_CROP;
      case 7: // focusCrop
        return ScaleType.FOCUS_CROP;
      default:
        // this method is supposed to be called only when XML attribute is specified.
        throw new RuntimeException("XML attribute not specified!");
    }
  }
}

這個(gè)類主要干xml中拿AttributeSet解析奕污,沒有包括java代碼自己手動動態(tài)設(shè)置的。
好了通過builder模式我們拿到GenericDraweeHierarchy
GenericDraweeHierarchy:

/**
 * A SettableDraweeHierarchy that displays placeholder image until the actual image is set.
 * If provided, failure image will be used in case of failure (placeholder otherwise).
 * If provided, retry image will be used in case of failure when retrying is enabled.
 * If provided, progressbar will be displayed until fully loaded.
 * Each image can be displayed with a different scale type (or no scaling at all).
 * Fading between the layers is supported. Rounding is supported.
 *
 * <p>
 * Example hierarchy with a placeholder, retry, failure and the actual image:
 *  <pre>
 *  o RootDrawable (top level drawable)
 *  |
 *  +--o FadeDrawable
 *     |
 *     +--o ScaleTypeDrawable (placeholder branch, optional)
 *     |  |
 *     |  +--o Drawable (placeholder image)
 *     |
 *     +--o ScaleTypeDrawable (actual image branch)
 *     |  |
 *     |  +--o ForwardingDrawable (actual image wrapper)
 *     |     |
 *     |     +--o Drawable (actual image)
 *     |
 *     +--o null (progress bar branch, optional)
 *     |
 *     +--o Drawable (retry image branch, optional)
 *     |
 *     +--o ScaleTypeDrawable (failure image branch, optional)
 *        |
 *        +--o Drawable (failure image)
 *  </pre>
 *
 * <p>
 * Note:
 * <ul>
 * <li> RootDrawable and FadeDrawable are always created.
 * <li> All branches except the actual image branch are optional (placeholder, failure, retry,
 * progress bar). If some branch is not specified it won't be created. Index in FadeDrawable will
 * still be reserved though.
 * <li> If overlays and/or background are specified, they are added to the same fade drawable, and
 * are always being displayed.
 * <li> ScaleType and Matrix transformations will be added only if specified. If both are
 * unspecified, then the branch for that image is attached to FadeDrawable directly. Matrix
 * transformation is only supported for the actual image, and it is not recommended to be used.
 * <li> Rounding, if specified, is applied to all layers. Rounded drawable can either wrap
 * FadeDrawable, or if leaf rounding is specified, each leaf drawable will be rounded separately.
 * <li> A particular drawable instance should be used by only one DH. If more than one DH is being
 * built with the same builder, different drawable instances must be specified for each DH.
 * </ul>
 */
public class GenericDraweeHierarchy implements SettableDraweeHierarchy {

  private static final int BACKGROUND_IMAGE_INDEX = 0;
  private static final int PLACEHOLDER_IMAGE_INDEX = 1;
  private static final int ACTUAL_IMAGE_INDEX = 2;
  private static final int PROGRESS_BAR_IMAGE_INDEX = 3;
  private static final int RETRY_IMAGE_INDEX = 4;
  private static final int FAILURE_IMAGE_INDEX = 5;
  private static final int OVERLAY_IMAGES_INDEX = 6;

  private final Drawable mEmptyActualImageDrawable = new ColorDrawable(Color.TRANSPARENT);

  private final Resources mResources;
  private @Nullable RoundingParams mRoundingParams;

  private final RootDrawable mTopLevelDrawable;
  private final FadeDrawable mFadeDrawable;
  private final ForwardingDrawable mActualImageWrapper;

  GenericDraweeHierarchy(GenericDraweeHierarchyBuilder builder) {
    mResources = builder.getResources();
    mRoundingParams = builder.getRoundingParams();

    mActualImageWrapper = new ForwardingDrawable(mEmptyActualImageDrawable);

    int numOverlays = (builder.getOverlays() != null) ? builder.getOverlays().size() : 1;
    numOverlays += (builder.getPressedStateOverlay() != null) ? 1 : 0;

    // layer indices and count
    int numLayers = OVERLAY_IMAGES_INDEX + numOverlays;

    // array of layers
    Drawable[] layers = new Drawable[numLayers];
    layers[BACKGROUND_IMAGE_INDEX] = buildBranch(builder.getBackground(), null);
    layers[PLACEHOLDER_IMAGE_INDEX] = buildBranch(
        builder.getPlaceholderImage(),
        builder.getPlaceholderImageScaleType());
    layers[ACTUAL_IMAGE_INDEX] = buildActualImageBranch(
        mActualImageWrapper,
        builder.getActualImageScaleType(),
        builder.getActualImageFocusPoint(),
        builder.getActualImageMatrix(),
        builder.getActualImageColorFilter());
    layers[PROGRESS_BAR_IMAGE_INDEX] = buildBranch(
        builder.getProgressBarImage(),
        builder.getProgressBarImageScaleType());
    layers[RETRY_IMAGE_INDEX] = buildBranch(
        builder.getRetryImage(),
        builder.getRetryImageScaleType());
    layers[FAILURE_IMAGE_INDEX] = buildBranch(
        builder.getFailureImage(),
        builder.getFailureImageScaleType());
    if (numOverlays > 0) {
      int index = 0;
      if (builder.getOverlays() != null) {
        for (Drawable overlay : builder.getOverlays()) {
          layers[OVERLAY_IMAGES_INDEX + index++] = buildBranch(overlay, null);
        }
      } else {
        index = 1; // reserve space for one overlay
      }
      if (builder.getPressedStateOverlay() != null) {
        layers[OVERLAY_IMAGES_INDEX + index] = buildBranch(builder.getPressedStateOverlay(), null);
      }
    }

    // fade drawable composed of layers
    mFadeDrawable = new FadeDrawable(layers);
    mFadeDrawable.setTransitionDuration(builder.getFadeDuration());

    // rounded corners drawable (optional)
    Drawable maybeRoundedDrawable =
        WrappingUtils.maybeWrapWithRoundedOverlayColor(mFadeDrawable, mRoundingParams);

    // top-level drawable
    mTopLevelDrawable = new RootDrawable(maybeRoundedDrawable);
    mTopLevelDrawable.mutate();

    resetFade();
  }

  @Nullable
  private Drawable buildActualImageBranch(
      Drawable drawable,
      @Nullable ScaleType scaleType,
      @Nullable PointF focusPoint,
      @Nullable Matrix matrix,
      @Nullable ColorFilter colorFilter) {
    drawable.setColorFilter(colorFilter);
    drawable = WrappingUtils.maybeWrapWithScaleType(drawable, scaleType, focusPoint);
    drawable = WrappingUtils.maybeWrapWithMatrix(drawable, matrix);
    return drawable;
  }

  /** Applies scale type and rounding (both if specified). */
  @Nullable
  private Drawable buildBranch(@Nullable Drawable drawable, @Nullable ScaleType scaleType) {
    drawable = WrappingUtils.maybeApplyLeafRounding(drawable, mRoundingParams, mResources);
    drawable = WrappingUtils.maybeWrapWithScaleType(drawable, scaleType);
    return drawable;
  }

  private void fadeOutBranches() {
    fadeOutLayer(PLACEHOLDER_IMAGE_INDEX);
    fadeOutLayer(ACTUAL_IMAGE_INDEX);
    fadeOutLayer(PROGRESS_BAR_IMAGE_INDEX);
    fadeOutLayer(RETRY_IMAGE_INDEX);
    fadeOutLayer(FAILURE_IMAGE_INDEX);
  }

  @Override
  public Drawable getTopLevelDrawable() {
    return mTopLevelDrawable;
  }

  .......

  @Override
  public void setRetry(Throwable throwable) {
    mFadeDrawable.beginBatchMode();
    fadeOutBranches();
    if (mFadeDrawable.getDrawable(RETRY_IMAGE_INDEX) != null) {
      fadeInLayer(RETRY_IMAGE_INDEX);
    } else {
      fadeInLayer(PLACEHOLDER_IMAGE_INDEX);
    }
    mFadeDrawable.endBatchMode();
  }

  @Override
  public void setControllerOverlay(@Nullable Drawable drawable) {
    mTopLevelDrawable.setControllerOverlay(drawable);
  }

  // Helper methods for accessing layers

  /**
   * Gets the lowest parent drawable for the layer at the specified index.
   *
   * Following drawables are considered as parents: FadeDrawable, MatrixDrawable, ScaleTypeDrawable.
   * This is because those drawables are added automatically by the hierarchy (if specified),
   * whereas their children are created externally by the client code. When we need to change the
   * previously set drawable this is the parent whose child needs to be replaced.
   */
  private DrawableParent getParentDrawableAtIndex(int index) {
    DrawableParent parent = mFadeDrawable.getDrawableParentForIndex(index);
    if (parent.getDrawable() instanceof MatrixDrawable) {
      parent = (MatrixDrawable) parent.getDrawable();
    }
    if (parent.getDrawable() instanceof ScaleTypeDrawable) {
      parent = (ScaleTypeDrawable) parent.getDrawable();
    }
    return parent;
  }

  /**
   * Sets the drawable at the specified index while keeping the old scale type and rounding.
   * In case the given drawable is null, scale type gets cleared too.
   */
  private void setChildDrawableAtIndex(int index, @Nullable Drawable drawable) {
    if (drawable == null) {
      mFadeDrawable.setDrawable(index, null);
      return;
    }
    drawable = WrappingUtils.maybeApplyLeafRounding(drawable, mRoundingParams, mResources);
    getParentDrawableAtIndex(index).setDrawable(drawable);
  }

  /**
   * Gets the ScaleTypeDrawable at the specified index.
   * In case there is no child at the specified index, a NullPointerException is thrown.
   * In case there is a child, but the ScaleTypeDrawable does not exist,
   * the child will be wrapped with a new ScaleTypeDrawable.
   */
  private ScaleTypeDrawable getScaleTypeDrawableAtIndex(int index) {
    DrawableParent parent = getParentDrawableAtIndex(index);
    if (parent instanceof ScaleTypeDrawable) {
      return (ScaleTypeDrawable) parent;
    } else {
      return WrappingUtils.wrapChildWithScaleType(parent, ScaleType.FIT_XY);
    }
  }

  .......

}

這個(gè)類實(shí)現(xiàn)SettableDraweeHierarchy液走,這貨將hold住一個(gè) placeholder image(默認(rèn)圖)碳默,直到新圖被裝備好替換上來,這個(gè)類可以支持failure image(下載失斣悼簟)和retry image(下載重試)和 progressbar 更新數(shù)據(jù)嘱根,
這個(gè)類構(gòu)造方法就是把層次分好,一層層繪制巷懈。
最后GenericDraweeView會把SettableDraweeHierarchy設(shè)置到AbstractDraweeController抽象父類中该抒,實(shí)現(xiàn)類是PipelineDraweeController,在sumbit()訂閱回掉中顶燕,更新界面數(shù)據(jù)和層次繪制凑保。
接著再看基類:


/**
 * View that displays a {@link DraweeHierarchy}.
 *
 * <p> Hierarchy should be set prior to using this view. See {@code setHierarchy}. Because creating
 * a hierarchy is an expensive operation, it is recommended this be done once per view, typically
 * near creation time.
 *
 * <p> In order to display an image, controller has to be set. See {@code setController}.

 * <p> Although ImageView is subclassed instead of subclassing View directly, this class does not
 * support ImageView's setImageXxx, setScaleType and similar methods. Extending ImageView is a short
 * term solution in order to inherit some of its implementation (padding calculations, etc.).
 * This class is likely to be converted to extend View directly in the future, so avoid using
 * ImageView's methods and properties.
 */
public class DraweeView<DH extends DraweeHierarchy> extends ImageView {

  private final AspectRatioMeasure.Spec mMeasureSpec = new AspectRatioMeasure.Spec();
  private float mAspectRatio = 0;
  private DraweeHolder<DH> mDraweeHolder;
  private boolean mInitialised = false;

  ......

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public DraweeView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context,attrs,defStyleAttr,defStyleRes);
    init(context);
  }

  /** This method is idempotent so it only has effect the first time it's called */
  private void init(Context context) {
    if (mInitialised) {
      return;
    }
    mInitialised = true;
    mDraweeHolder = DraweeHolder.create(null, context);
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      ColorStateList imageTintList = getImageTintList();
      if (imageTintList == null) {
        return;
      }
      setColorFilter(imageTintList.getDefaultColor());
    }
  }

  /** Sets the hierarchy. */
  public void setHierarchy(DH hierarchy) {
    mDraweeHolder.setHierarchy(hierarchy);
    super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());
  }

  /** Returns whether the hierarchy is set or not. */
  public boolean hasHierarchy() {
    return mDraweeHolder.hasHierarchy();
  }

  /** Gets the top-level drawable if hierarchy is set, null otherwise. */
  @Nullable public Drawable getTopLevelDrawable() {
    return mDraweeHolder.getTopLevelDrawable();
  }

  /** Sets the controller. */
  public void setController(@Nullable DraweeController draweeController) {
    mDraweeHolder.setController(draweeController);
    super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());
  }

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

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

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

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

  ........

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

}

這個(gè)類是imageview包裝,但沒有實(shí)現(xiàn)imageview方法和屬性涌攻,為了未來的擴(kuò)展愉适,創(chuàng)建好了時(shí)候,必須要把Hierarchy創(chuàng)建好癣漆,這個(gè)類接收IMS和WMS事件回掉了维咸,開啟生命周期維護(hù)和任務(wù)
這個(gè)類還有個(gè)重要成員屬性代理類DraweeHolder,類似Activity中mInstrumentation執(zhí)行一樣

總結(jié):SimpleDraweeView相當(dāng)與包裝了ImageView, 自身通過設(shè)置controller和PipelineDraweeController類綁定,自身接收ims和wsm事件通過DraweeHolder向controller類中安排任務(wù)癌蓖,controller通過訂閱的模式向DataSource(model層)生成回調(diào)接口瞬哼,再通過Hierarchy去控制刷新SimpleDraweeView的layer層次view樹

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市租副,隨后出現(xiàn)的幾起案子坐慰,更是在濱河造成了極大的恐慌,老刑警劉巖用僧,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件结胀,死亡現(xiàn)場離奇詭異,居然都是意外死亡责循,警方通過查閱死者的電腦和手機(jī)糟港,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來院仿,“玉大人秸抚,你說我怎么就攤上這事〈醯妫” “怎么了剥汤?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長排惨。 經(jīng)常有香客問我吭敢,道長,這世上最難降的妖魔是什么暮芭? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任省有,我火速辦了婚禮,結(jié)果婚禮上谴麦,老公的妹妹穿的比我還像新娘蠢沿。我一直安慰自己,他們只是感情好匾效,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布舷蟀。 她就那樣靜靜地躺著,像睡著了一般面哼。 火紅的嫁衣襯著肌膚如雪野宜。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天魔策,我揣著相機(jī)與錄音匈子,去河邊找鬼。 笑死闯袒,一個(gè)胖子當(dāng)著我的面吹牛虎敦,可吹牛的內(nèi)容都是我干的游岳。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼其徙,長吁一口氣:“原來是場噩夢啊……” “哼胚迫!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唾那,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤访锻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后闹获,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體期犬,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年避诽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了龟虎。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,722評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茎用,死狀恐怖遣总,靈堂內(nèi)的尸體忽然破棺而出睬罗,到底是詐尸還是另有隱情轨功,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布容达,位于F島的核電站古涧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏花盐。R本人自食惡果不足惜羡滑,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望算芯。 院中可真熱鬧柒昏,春花似錦、人聲如沸熙揍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽届囚。三九已至有梆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間意系,已是汗流浹背泥耀。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛔添,地道東北人痰催。 一個(gè)月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓兜辞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親陨囊。 傳聞我的和親對象是個(gè)殘疾皇子弦疮,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容