Fresco SimpleDraweeView界面源码分析

Fresco 网络请求在前面2篇介绍完了,我们来看看Fresco Hierarchy(view分层结构)

/**
 * This view takes a uri as input and internally builds and sets a controller.
 *
 * 

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 sDraweeControllerBuilderSupplier; /** Initializes {@link SimpleDraweeView} with supplier of Drawee controller builders. */ public static void initialize( Supplier 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); } }

这个类用于你界面布局,父类是imageview,他会自己创建DraweeController和自身绑定,关于Supplier是外部提供关于下载和维护,Cache提供的工厂类,在Frescoc:init()时候创建。
SimpleDraweeView用法:

Fresco SimpleDraweeView界面源码分析_第1张图片
Paste_Image.png

SimpleDraweeView详细用法

感觉还是少了很多东西,接着我们看下基类:

/**
 * 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 {

  .......

  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布局属性写法的,最后它会初始化一个Hierarchy
来看看GenericDraweeHierarchyBuilder和GenericDraweeHierarchyInflater干了啥
GenericDraweeHierarchyBuilder:

/**
 * Class to construct a {@link GenericDraweeHierarchy}.
 *
 * 

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

这个类一看就是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!");
    }
  }
}

这个类主要干xml中拿AttributeSet解析,没有包括java代码自己手动动态设置的。
好了通过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.
 *
 * 

* Example hierarchy with a placeholder, retry, failure and the actual image: *

 *  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)
 *  
* *

* Note: *

    *
  • RootDrawable and FadeDrawable are always created. *
  • 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. *
  • If overlays and/or background are specified, they are added to the same fade drawable, and * are always being displayed. *
  • 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. *
  • 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. *
  • 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. *
*/ 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); } } ....... }

这个类实现SettableDraweeHierarchy,这货将hold住一个 placeholder image(默认图),直到新图被装备好替换上来,这个类可以支持failure image(下载失败)和retry image(下载重试)和 progressbar 更新数据,
这个类构造方法就是把层次分好,一层层绘制。
最后GenericDraweeView会把SettableDraweeHierarchy设置到AbstractDraweeController抽象父类中,实现类是PipelineDraweeController,在sumbit()订阅回掉中,更新界面数据和层次绘制。
接着再看基类:


/**
 * View that displays a {@link DraweeHierarchy}.
 *
 * 

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. * *

In order to display an image, controller has to be set. See {@code setController}. *

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 extends ImageView { private final AspectRatioMeasure.Spec mMeasureSpec = new AspectRatioMeasure.Spec(); private float mAspectRatio = 0; private DraweeHolder 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); } }

这个类是imageview包装,但没有实现imageview方法和属性,为了未来的扩展,创建好了时候,必须要把Hierarchy创建好,这个类接收IMS和WMS事件回掉了,开启生命周期维护和任务
这个类还有个重要成员属性代理类DraweeHolder,类似Activity中mInstrumentation执行一样

总结:SimpleDraweeView相当与包装了ImageView, 自身通过设置controller和PipelineDraweeController类绑定,自身接收ims和wsm事件通过DraweeHolder向controller类中安排任务,controller通过订阅的模式向DataSource(model层)生成回调接口,再通过Hierarchy去控制刷新SimpleDraweeView的layer层次view树

你可能感兴趣的:(Fresco SimpleDraweeView界面源码分析)