Fresco源码赏析 之 图片显示流程

  转载请注明出处:http://blog.csdn.net/u014614038/article/details/51498068

 上文大概将Fresco的基本流程通了一遍,就是Frosco是如何实现了只是简单调用了setImageUrl的方法后自动将所有事情做好,这里包含很多的流程,上文大概把这些流程过了一遍,这篇文章打算将接说一下上文没有说到的一些东西,就是拿到数据后它是如何处理的,是怎么显示出来的。


上文 Fresco源码赏析 之基本流程可以看这里:

http://blog.csdn.net/u014614038/article/details/51480072     

根据上文的可以知道了,fresco采用的是典型的mvc模式,DraweeHierarchy 负责的是跟显示相关的,DraweeController 负责的是后台相关的,DraweeHolder主要是统筹两者的,其他还有一些事件记录等操作。我们在这里主要关心的是DraweeHierarchy 。

上文知道了一点,SimpleDraweeView它的controller是PipelineDraweeController,在它的onattach方法中会监听并获取到数据:


  @Override
  public void onAttach() {
    if (FLog.isLoggable(FLog.VERBOSE)) {
      FLog.v(
          TAG,
          "controller %x %s: onAttach: %s",
          System.identityHashCode(this),
          mId,
          mIsRequestSubmitted ? "request already submitted" : "request needs submit");
    }
    mEventTracker.recordEvent(Event.ON_ATTACH_CONTROLLER);
    Preconditions.checkNotNull(mSettableDraweeHierarchy);
    mDeferredReleaser.cancelDeferredRelease(this);
    mIsAttached = true;
    if (!mIsRequestSubmitted) {
      submitRequest();//这里提交了请求
    }
  }


protected void submitRequest() {
    mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT);
    getControllerListener().onSubmit(mId, mCallerContext);
    mSettableDraweeHierarchy.setProgress(0, true);
    mIsRequestSubmitted = true;
    mHasFetchFailed = false;
    mDataSource = getDataSource();//获取数据
    if (FLog.isLoggable(FLog.VERBOSE)) {
      FLog.v(
          TAG,
          "controller %x %s: submitRequest: dataSource: %x",
          System.identityHashCode(this),
          mId,
          System.identityHashCode(mDataSource));
    }
    final String id = mId;
    final boolean wasImmediate = mDataSource.hasResult();
    final DataSubscriber<T> dataSubscriber =
        new BaseDataSubscriber<T>() {
          @Override//新数据回调监听
          public void onNewResultImpl(DataSource<T> dataSource) {
            // isFinished must be obtained before image, otherwise we might set intermediate result
            // as final image.
            boolean isFinished = dataSource.isFinished();
            T image = dataSource.getResult();
            if (image != null) {
              onNewResultInternal(id, dataSource, image, isFinished, wasImmediate);
            } else if (isFinished) {
              onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true);
            }
          }
          @Override//失败回调监听
          public void onFailureImpl(DataSource<T> dataSource) {
            onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true);
          }
        };
        
    mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor);//传入ui线程与监听
  }


mDataSource = getDataSource()是用于获取数据的,这个其实是启动后台服务进行的不是即时获取的,所以它传入了一个数据回调监听以及UI线程,当数据返回的时候这个操作要通过ui线程中执行进行相应的界面操作。

DataSource是一个接口类,很容易就找到了它 的实现的抽象类:AbstractDataSource,这个是抽象父类,不同类型的数据有不同的子类:


这个就不看了,我们看看那个mDataSource.subscribe方法:


  @Override
  public void subscribe(final DataSubscriber<T> dataSubscriber, final Executor executor) {
    Preconditions.checkNotNull(dataSubscriber);
    Preconditions.checkNotNull(executor);
    boolean shouldNotify;

    synchronized(this) {
      if (mIsClosed) {
        return;
      }

      if (mDataSourceStatus == DataSourceStatus.IN_PROGRESS) {
    	  //每个Ui线程以及对应数据存起来,刷新的会遍历集合全部刷新
        mSubscribers.add(Pair.create(dataSubscriber, executor));
      }

      shouldNotify = hasResult() || isFinished() || wasCancelled();
    }

    if (shouldNotify) {
    	//如果需要刷新就进行刷新操作
      notifyDataSubscriber(dataSubscriber, executor, hasFailed(), wasCancelled());
    }
  }


 private void notifyDataSubscriber(
      final DataSubscriber<T> dataSubscriber,
      final Executor executor,
      final boolean isFailure,
      final boolean isCancellation) {
    executor.execute(//在ui线程中执行相应操作
        new Runnable() {
          @Override
          public void run() {
            if (isFailure) {//这里是相应的数据监听进行的回调
              dataSubscriber.onFailure(AbstractDataSource.this);
            } else if (isCancellation) {
              dataSubscriber.onCancellation(AbstractDataSource.this);
            } else {
              dataSubscriber.onNewResult(AbstractDataSource.this);
            }
          }
        });
  }

看了没有,最终会通过ui线程进行相应数据回调,可以验证了现在是执行相应的ui操作了,我们看回去那个数据回调:


  final DataSubscriber<T> dataSubscriber =
        new BaseDataSubscriber<T>() {
          @Override//新数据回调监听
          public void onNewResultImpl(DataSource<T> dataSource) {
            // isFinished must be obtained before image, otherwise we might set intermediate result
            // as final image.
            boolean isFinished = dataSource.isFinished();
            T image = dataSource.getResult();
            if (image != null) {
              onNewResultInternal(id, dataSource, image, isFinished, wasImmediate);
            } else if (isFinished) {
              onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true);
            }
          }
          @Override//失败回调监听
          public void onFailureImpl(DataSource<T> dataSource) {
            onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true);
          }
        };


 private void onNewResultInternal(
      String id,
      DataSource<T> dataSource,
      @Nullable T image,
      boolean isFinished,
      boolean wasImmediate) {
    // ignore late callbacks (data source that returned the new result is not the one we expected)
    if (!isExpectedDataSource(id, dataSource)) {
      logMessageAndImage("ignore_old_datasource @ onNewResult", image);
      releaseImage(image);
      dataSource.close();
      return;
    }
    mEventTracker.recordEvent(
        isFinished ? Event.ON_DATASOURCE_RESULT : Event.ON_DATASOURCE_RESULT_INT);
    // create drawable
    Drawable drawable;
    try {
      drawable = createDrawable(image);
    } catch (Exception exception) {
      logMessageAndImage("drawable_failed @ onNewResult", image);
      releaseImage(image);
      onFailureInternal(id, dataSource, exception, isFinished);
      return;
    }
    T previousImage = mFetchedImage;
    Drawable previousDrawable = mDrawable;
    mFetchedImage = image;
    mDrawable = drawable;
    try {
      // set the new image
      if (isFinished) {
        logMessageAndImage("set_final_result @ onNewResult", image);
        mDataSource = null;
        //=======进行显示image=============
        mSettableDraweeHierarchy.setImage(drawable, wasImmediate, 100);
        getControllerListener().onFinalImageSet(id, getImageInfo(image), getAnimatable());
        // IMPORTANT: do not execute any instance-specific code after this point
      } else {
        logMessageAndImage("set_intermediate_result @ onNewResult", image);
        int progress = getProgress(dataSource, image);
        mSettableDraweeHierarchy.setImage(drawable, wasImmediate, progress);
        getControllerListener().onIntermediateImageSet(id, getImageInfo(image));
        // IMPORTANT: do not execute any instance-specific code after this point
      }
    } finally {
      if (previousDrawable != null && previousDrawable != drawable) {
        releaseDrawable(previousDrawable);
      }
      if (previousImage != null && previousImage != image) {
        logMessageAndImage("release_previous_result @ onNewResult", previousImage);
        releaseImage(previousImage);
      }
    }
  }



这里已经是在ui线程中进行操作了,包括一下事件记录,日志记录什么的,最后看到核心那句了,完成后显示图片: mSettableDraweeHierarchy.setImage(drawable, wasImmediate, 100);,所以又验证了说了那样,最终还是通过DraweeHierarchy将获取的数据后显示出来。在这里这个DraweeHierarchy是它 的子类SettableDraweeHierarchy,这是个接口类,官方解析是这样的:

/**
* Interface that represents a settable Drawee hierarchy. Hierarchy should display a placeholder
* image until the actual image is set. In case of a failure, hierarchy can choose to display
* a failure image.
*
* <p>IMPORTANT: methods of this interface are to be used by controllers ONLY!
*
* <p>
* Example hierarchy:
*
* o FadeDrawable (top level drawable)
* |
* +--o ScaleTypeDrawable
* | |
* | +--o ColorDrawable (placeholder image)
* |
* +--o ScaleTypeDrawable
* | |
* | +--o BitmapDrawable (failure image)
* |
* +--o ScaleTypeDrawable
* |
* +--o SettableDrawable
* |
* +--o BitmapDrawable (actual image)
*
* SettableDraweeHierarchy in the given example has a FadeDrawable as its top level drawable.
* Top level drawable can be immediately put into view. Once the actual image is ready, it will
* be set to the hierarchy's SettableDrawable and fade animation between the placeholder and the
* actual image will be initiated. In case of failure, hierarchy will switch to failure image.
* All image branches are wrapped with ScaleType drawable which allows separate scale type to be
* applied on each.
*
*/






好像没看懂多少,我们看看这个的实现类,发现只有一个类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.
 *
 * <p><pre name="code" class="java">
 *        +--o Drawable (failure image)

* Example hierarchy with placeholder, retry, failure and one actual image: * <pre> * o FadeDrawable (top level drawable) * | * +--o ScaleTypeDrawable * | | * | +--o Drawable (placeholder image) * | * +--o ScaleTypeDrawable * | | * | +--o SettableDrawable * | | * | +--o Drawable (actual image) * | * +--o ScaleTypeDrawable * | | * | +--o Drawable (retry image) * | * +--o ScaleTypeDrawable * | * +--o Drawable (failure image) * </pre> * * <p> * Note: * - ScaleType and Matrix transformations will be added only if specified. If both are unspecified, * then the branch for that image will be attached directly. * - It is not permitted to set both ScaleType transformation and Matrix transformation for the * same image. * - A Matrix transformation is only supported for actual image. * - All branches (placeholder, failure, retry, actual image, progressBar) are optional. * If some branch is not specified it won't be created. The exception is placeholder branch, * which will, if not specified, be created with a transparent drawable. * - If overlays and/or backgrounds are specified, they are added to the same fade drawable, and * are always displayed. * - Instance of some drawable 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. */

 

粗略来说就是它在真正的图片数据到来前会显示一些占位符图片,比如图片加载失败时显示的图片、点击重试时显示的图片、加载使的进度条等,其实它是一个有层次结构的数据体,每一个不同图片是一个层,加载中的显示的图片是一个层、失败后显示的图片是一个层、真正的数据是一个层、在不同的状态是隐藏或者显示需要的层来达到效果。它的层次结构如下那样:

 o FadeDrawable (top level drawable)
 *     |
 *     +--o ScaleTypeDrawable
 *     |  |
 *     |  +--o Drawable (placeholder image)
 *     |
 *     +--o ScaleTypeDrawable
 *     |  |
 *     |  +--o SettableDrawable
 *     |     |
 *     |     +--o Drawable (actual image)
 *     |
 *     +--o ScaleTypeDrawable
 *     |  |
 *     |  +--o Drawable (retry image)
 *     |
 *     +--o ScaleTypeDrawable
 *        |
 *        +--o Drawable (failure image)

我觉得,真正控制的只是FadeDrawable而已,也就是说只有一个drawable而已,那些加载失败后显示的图片、重试时显示的图片等只是叠加画在上面而已。具体看看是不是这样:

先看看GenericDraweeHierarchy的成员变量,它有不同的drawable以及对应的index:

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

  private final Resources mResources;

  private final Drawable mTopLevelDrawable;
  private final FadeDrawable mFadeDrawable;
  private final SettableDrawable mActualImageSettableDrawable;

  private final int mPlaceholderImageIndex;
  private final int mProgressBarImageIndex;
  private final int mActualImageIndex;
  private final int mRetryImageIndex;
  private final int mFailureImageIndex;
  private final int mControllerOverlayIndex;

看看那个setImage方法:

@Override
  public void setImage(Drawable drawable, boolean immediate, int progress) {
    drawable = maybeApplyRounding(mRoundingParams, mResources, drawable);
    drawable.mutate();
    mActualImageSettableDrawable.setDrawable(drawable);//这里传进去的是真正的图片数据
    mFadeDrawable.beginBatchMode();
    fadeOutBranches();//隐藏其他层
    fadeInLayer(mActualImageIndex);//显示真正数据层
    setProgress(progress);//设置进度
    if (immediate) {
      mFadeDrawable.finishTransitionImmediately();//刷新
    }
    mFadeDrawable.endBatchMode();
  }


 private void fadeInLayer(int index) {
    if (index >= 0) {
      mFadeDrawable.fadeInLayer(index);
    }
  }


这里我们可以确定了一点就是,图片显示的控制确实通过FadeDrawable进行控制的,我们看看这个FadeDrawable:

/**
 * A drawable that fades to the specific layer.
 *
 * <p> Arbitrary number of layers is supported. 5 Different fade methods are supported.
 * Once the transition starts we will animate layers in or out based on used fade method.
 * fadeInLayer fades in specified layer to full opacity.
 * fadeOutLayer fades out specified layer to zero opacity.
 * fadeOutAllLayers fades out all layers to zero opacity.
 * fadeToLayer fades in specified layer to full opacity, fades out all other layers to zero opacity.
 * fadeUpToLayer fades in all layers up to specified layer to full opacity and
 * fades out all other layers to zero opacity.
 *
 */
public class FadeDrawable extends ArrayDrawable


意思就是说通过它去隐藏或者显示对应的层的,它在构造器初始化是需要传入需要的各个层:


/**
   * Creates a new fade drawable.
   * The first layer is displayed with full opacity whereas all other layers are invisible.
   * @param layers layers to fade between
   */
  public FadeDrawable(Drawable[] layers) {
    super(layers);
    Preconditions.checkState(layers.length >= 1, "At least one layer required!");
    mLayers = layers;
    mStartAlphas = new int[layers.length];
    mAlphas = new int[layers.length];
    mAlpha = 255;
    mIsLayerOn = new boolean[layers.length];
    mPreventInvalidateCount = 0;
    resetInternal();
  }


每个层还有对应的透明度之类的数据。因为它是drawable,所以最终处理还是在ondraw方法里面,我们看看这个方法:

 @Override
  public void draw(Canvas canvas) {
    boolean done = true;
    float ratio;

    switch (mTransitionState) {//这个是根据数据加载传输时的状态执行
      case TRANSITION_STARTING:
        // initialize start alphas and start time
        System.arraycopy(mAlphas, 0, mStartAlphas, 0, mLayers.length);
        mStartTimeMs = getCurrentTimeMs();
        // if the duration is 0, update alphas to the target opacities immediately
        ratio = (mDurationMs == 0) ? 1.0f : 0.0f;
        // if all the layers have reached their target opacity, transition is done
        done = updateAlphas(ratio);
        mTransitionState = done ? TRANSITION_NONE : TRANSITION_RUNNING;
        break;

      case TRANSITION_RUNNING:
        Preconditions.checkState(mDurationMs > 0);
        // determine ratio based on the elapsed time
        ratio = (float) (getCurrentTimeMs() - mStartTimeMs) / mDurationMs;
        // if all the layers have reached their target opacity, transition is done
        done = updateAlphas(ratio);
        mTransitionState = done ? TRANSITION_NONE : TRANSITION_RUNNING;
        break;

      case TRANSITION_NONE:
        // there is no transition in progress and mAlphas should be left as is.
        done = true;
        break;
    }

    for (int i = 0; i < mLayers.length; i++) {//看到核心了,实际就是把所有的层画在同一个canvas上
      drawDrawableWithAlpha(canvas, mLayers[i], mAlphas[i] * mAlpha / 255);
    }

    if (!done) {
      invalidateSelf();
    }
  }

看到这里忽然明白了吧,FadeDrawable是几个drawable,一切显示相关的图片会画在这个drawable上面,在不同的加载状态下显示或者隐藏相应的层就可以,而它的隐藏其实就是将透明度调到0而已,上面的初始化时有透明度的数据就是了。


现在知道为何GenericDraweeHierarchy的成员变量有不同的drawable了吧,就是不同的层的drawable还有对应的index,GenericDraweeHierarchy拿到FadeDrawable (top level drawable)以及各个层的index进行控制隐藏或者显示就可以。


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

    int numLayers = 0;

    // backgrounds
    int numBackgrounds = (builder.getBackgrounds() != null) ? builder.getBackgrounds().size() : 0;
    int backgroundsIndex = numLayers;
    numLayers += numBackgrounds;//背景层

    // placeholder image branch
    Drawable placeholderImageBranch = builder.getPlaceholderImage();
    if (placeholderImageBranch == null) {
      placeholderImageBranch = getEmptyPlaceholderDrawable();
    }
    placeholderImageBranch = maybeApplyRounding(
        mRoundingParams,
        mResources,
        placeholderImageBranch);
    placeholderImageBranch = maybeWrapWithScaleType(
        placeholderImageBranch,
        builder.getPlaceholderImageScaleType());
    mPlaceholderImageIndex = numLayers++;//占位符层

    // actual image branch
    Drawable actualImageBranch = null;
    mActualImageSettableDrawable = new SettableDrawable(mEmptyActualImageDrawable);
    actualImageBranch = mActualImageSettableDrawable;
    actualImageBranch = maybeWrapWithScaleType(
        actualImageBranch,
        builder.getActualImageScaleType(),
        builder.getActualImageFocusPoint());
    actualImageBranch = maybeWrapWithMatrix(
        actualImageBranch,
        builder.getActualImageMatrix());
    actualImageBranch.setColorFilter(builder.getActualImageColorFilter());
    mActualImageIndex = numLayers++;//真正数据层

    // progressBar image branch
    Drawable progressBarImageBranch = builder.getProgressBarImage();
    if (progressBarImageBranch != null) {
      progressBarImageBranch = maybeWrapWithScaleType(
          progressBarImageBranch,
          builder.getProgressBarImageScaleType());
      mProgressBarImageIndex = numLayers++;//进度条层
    } else {
      mProgressBarImageIndex = -1;
    }

    // retry image branch
    Drawable retryImageBranch = builder.getRetryImage();
    if (retryImageBranch != null) {
      retryImageBranch = maybeWrapWithScaleType(
          retryImageBranch,
          builder.getRetryImageScaleType());
      mRetryImageIndex = numLayers++;//重试层
    } else {
      mRetryImageIndex = -1;
    }

    // failure image branch
    Drawable failureImageBranch = builder.getFailureImage();
    if (failureImageBranch != null) {
      failureImageBranch = maybeWrapWithScaleType(
          failureImageBranch,
          builder.getFailureImageScaleType());
      mFailureImageIndex = numLayers++;//失败显示层
    } else {
      mFailureImageIndex = -1;
    }

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

    // controller overlay
    mControllerOverlayIndex = numLayers++;

    // array of layers
    Drawable[] layers = new Drawable[numLayers];
    if (numBackgrounds > 0) {
      int index = 0;
      for (Drawable background : builder.getBackgrounds()) {
        layers[backgroundsIndex + index++] = background;
      }
    }
    if (mPlaceholderImageIndex >= 0) {
      layers[mPlaceholderImageIndex] = placeholderImageBranch;
    }
    if (mActualImageIndex >= 0) {
      layers[mActualImageIndex] = actualImageBranch;
    }
    if (mProgressBarImageIndex >= 0) {
      layers[mProgressBarImageIndex] = progressBarImageBranch;
    }
    if (mRetryImageIndex >= 0) {
      layers[mRetryImageIndex] = retryImageBranch;
    }
    if (mFailureImageIndex >= 0) {
      layers[mFailureImageIndex] = failureImageBranch;
    }
    if (numOverlays > 0) {
      int index = 0;
      for (Drawable overlay : builder.getOverlays()) {
        layers[overlaysIndex + index++] = overlay;
      }
      if (builder.getPressedStateOverlay() != null) {
        layers[overlaysIndex + index++] = builder.getPressedStateOverlay();
      }
    }
    if (mControllerOverlayIndex >= 0) {
      layers[mControllerOverlayIndex] = mEmptyControllerOverlayDrawable;
    }

    Drawable root;

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

    // rounded corners drawable (optional)
    root = maybeWrapWithRoundedCorners(mRoundingParams, root);

    // top-level drawable
    mTopLevelDrawable = root;
    mTopLevelDrawable.mutate();

    resetFade();
  }


现在我们看看这些层的数据是怎么传递进来的,通过代码发现这个初始化只有一个地方调用到:

public GenericDraweeHierarchy build() {
    validate();
    return new GenericDraweeHierarchy(this);
  }


而这个会在GenericDraweeView(SimpleDraweeView的父类)初始化时执行了:


 private void inflateHierarchy(Context context, @Nullable AttributeSet attrs) {
    Resources resources = context.getResources();

    // fading animation defaults
    int fadeDuration = GenericDraweeHierarchyBuilder.DEFAULT_FADE_DURATION;
    // images & scale types defaults
    int placeholderId = 0;
    ScalingUtils.ScaleType placeholderScaleType
        = GenericDraweeHierarchyBuilder.DEFAULT_SCALE_TYPE;
    int retryImageId = 0;
    ScalingUtils.ScaleType retryImageScaleType =
        GenericDraweeHierarchyBuilder.DEFAULT_SCALE_TYPE;
    int failureImageId = 0;
    ScalingUtils.ScaleType failureImageScaleType =
        GenericDraweeHierarchyBuilder.DEFAULT_SCALE_TYPE;
    int progressBarId = 0;
    ScalingUtils.ScaleType progressBarScaleType =
        GenericDraweeHierarchyBuilder.DEFAULT_SCALE_TYPE;
    ScalingUtils.ScaleType actualImageScaleType =
        GenericDraweeHierarchyBuilder.DEFAULT_ACTUAL_IMAGE_SCALE_TYPE;
    int backgroundId = 0;
    int overlayId = 0;
    int pressedStateOverlayId = 0;
    // rounding defaults
    boolean roundAsCircle = false;
    int roundedCornerRadius = 0;
    boolean roundTopLeft = true;
    boolean roundTopRight = true;
    boolean roundBottomRight = true;
    boolean roundBottomLeft = true;
    int roundWithOverlayColor = 0;
    int roundingBorderWidth = 0;
    int roundingBorderColor = 0;
    int progressBarAutoRotateInterval = 0;


    if (attrs != null) {
      TypedArray gdhAttrs = context.obtainStyledAttributes(
          attrs,
          R.styleable.GenericDraweeView);
      try {
        // fade duration
        fadeDuration = gdhAttrs.getInt(
            R.styleable.GenericDraweeView_fadeDuration,
            fadeDuration);

        // placeholder image
        placeholderId = gdhAttrs.getResourceId(
            R.styleable.GenericDraweeView_placeholderImage,
            placeholderId);
        // placeholder image scale type
        placeholderScaleType = getScaleTypeFromXml(
            gdhAttrs,
            R.styleable.GenericDraweeView_placeholderImageScaleType,
            placeholderScaleType);

        // retry image
        retryImageId = gdhAttrs.getResourceId(
            R.styleable.GenericDraweeView_retryImage,
            retryImageId);
        // retry image scale type
        retryImageScaleType = getScaleTypeFromXml(
            gdhAttrs,
            R.styleable.GenericDraweeView_retryImageScaleType,
            retryImageScaleType);

        // failure image
        failureImageId = gdhAttrs.getResourceId(
            R.styleable.GenericDraweeView_failureImage,
            failureImageId);
        // failure image scale type
        failureImageScaleType = getScaleTypeFromXml(
            gdhAttrs,
            R.styleable.GenericDraweeView_failureImageScaleType,
            failureImageScaleType);

        // progress bar image
        progressBarId = gdhAttrs.getResourceId(
            R.styleable.GenericDraweeView_progressBarImage,
            progressBarId);
        // progress bar image scale type
        progressBarScaleType = getScaleTypeFromXml(
            gdhAttrs,
            R.styleable.GenericDraweeView_progressBarImageScaleType,
            progressBarScaleType);
        // progress bar auto rotate interval
        progressBarAutoRotateInterval = gdhAttrs.getInteger(
            R.styleable.GenericDraweeView_progressBarAutoRotateInterval,
            0);

        // actual image scale type
        actualImageScaleType = getScaleTypeFromXml(
            gdhAttrs,
            R.styleable.GenericDraweeView_actualImageScaleType,
            actualImageScaleType);

        // background
        backgroundId = gdhAttrs.getResourceId(
            R.styleable.GenericDraweeView_backgroundImage,
            backgroundId);

        // overlay
        overlayId = gdhAttrs.getResourceId(
            R.styleable.GenericDraweeView_overlayImage,
            overlayId);

        // pressedState overlay
        pressedStateOverlayId = gdhAttrs.getResourceId(
            R.styleable.GenericDraweeView_pressedStateOverlayImage,
            pressedStateOverlayId);

        // rounding parameters
        roundAsCircle = gdhAttrs.getBoolean(
            R.styleable.GenericDraweeView_roundAsCircle,
            roundAsCircle);
        roundedCornerRadius = gdhAttrs.getDimensionPixelSize(
            R.styleable.GenericDraweeView_roundedCornerRadius,
            roundedCornerRadius);
        roundTopLeft = gdhAttrs.getBoolean(
            R.styleable.GenericDraweeView_roundTopLeft,
            roundTopLeft);
        roundTopRight = gdhAttrs.getBoolean(
            R.styleable.GenericDraweeView_roundTopRight,
            roundTopRight);
        roundBottomRight = gdhAttrs.getBoolean(
            R.styleable.GenericDraweeView_roundBottomRight,
            roundBottomRight);
        roundBottomLeft = gdhAttrs.getBoolean(
            R.styleable.GenericDraweeView_roundBottomLeft,
            roundBottomLeft);
        roundWithOverlayColor = gdhAttrs.getColor(
            R.styleable.GenericDraweeView_roundWithOverlayColor,
            roundWithOverlayColor);
        roundingBorderWidth = gdhAttrs.getDimensionPixelSize(
            R.styleable.GenericDraweeView_roundingBorderWidth,
            roundingBorderWidth);
        roundingBorderColor = gdhAttrs.getColor(
            R.styleable.GenericDraweeView_roundingBorderColor,
            roundingBorderColor);
      }
      finally {
        gdhAttrs.recycle();
      }
    }

所以就这样,会在获取xml中设置的所有资源, 转载请注明出处:http://blog.csdn.net/u014614038/article/details/51498068



简单总结一下:

1.Fresco会的Hierarchy是有层次drawable的数据存储的地方,不同图片显示有不同的drawable,比如图片加载中显示图片、加载失败显示图片、点击重试显示图片、真正显示的图片,这些数据可以通过xml设置。


2.Fresco加载图片的不同状态会显示不同的层的drawable,其实这些层的drawable都画在一个drawable上,这个就是top level drawable,用于控制隐藏或者显示不同的层的drawable,隐藏方式只是通过设置不同drawable的透明度而已。


3.Fresco界面显示控制操作是在Hierarchy上,这个在数据回调监听时同时将操作的ui线程传递进去,所以所有的ui操作都在ui线程里面了,是安全的。











  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值