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线程里面了,是安全的。

时间: 2024-10-03 11:10:28

Fresco源码赏析 之 图片显示流程的相关文章

Cocos2dx源码赏析(1)之启动流程与主循环

Cocos2dx源码赏析(1)之启动流程与主循环 我们知道Cocos2dx是一款开源的跨平台游戏引擎,而学习开源项目一个较实用的办法就是读源码.所谓,"源码之前,了无秘密".而笔者从事的也是游戏开发工作,因此,通过梳理下源码的脉络,来加深对Cocos2dx游戏引擎的理解. 既然,Cocos2dx是跨平台的,那么,就有针对不同平台运行的入口以及维持引擎运转的"死循环".下面,就分别从Windows.Android.iOS三个平台说明下Cocos2dx从启动到进入主循环

Fresco源码赏析 之 基本流程

转载请注明出处:http://blog.csdn.net/u014614038/article/details/51480072 关于 Fresco Fresco 是一个强大的图片加载组件. Fresco 中设计有一个叫做 image pipeline 的模块.它负责从网络,从本地文件系统,本地资源加载图片.为了最大限度节省空间和CPU时间,它含有3级缓存设计(2级内存,1级文件). Fresco 中设计有一个叫做 Drawees 模块,方便地显示loading图,当图片不再显示在屏幕上时,及时

Fresco 源码浅析

前言 fresco是facebook主导的一个开源图片缓存库,从它提供的示例程序comparison来看,fresco貌似比其他的几个目前android主流的图片缓存库(glide,picasso,uil等)更快更节省内存.接下来就看看它到底是如何做到的. 一.背景: 1:lru与SoftReference那些年的爱恨情仇:很久很久以前,android的内存缓存还用SoftReference, 在2.3以后,垃圾回收机制被修改,软引用已不推荐用作缓存技术了,lru等才是正义.既然软引用已经不再推

Cocos2dx源码赏析(2)之渲染

Cocos2dx源码赏析(2)之渲染 这篇,继续从源码的角度来跟踪下Cocos2dx引擎的渲染过程,以此来梳理下Cocos2dx引擎是如何将精灵等元素显示在屏幕上的. 从上一篇对Cocos2dx启动流程的梳理中可知,Cocos2dx依靠通过各平台的入口启动引擎,并在循环中调用Director::mainLoop方法来维持引擎的各种逻辑: void Director::mainLoop() { if (_purgeDirectorInNextLoop) { _purgeDirectorInNext

Fresco源码解析 - 本地编译

第一次写专栏,如有表述不好或者理解错误的地方,请各位读者不吝赐教,本人一定虚心接受并第一时间改正. 作为专题第一篇,先从最简单的开始,顺便找找感觉. Fresco 是 facebook 在今年的 F8 大会上宣布开源的一个用于加载图片的库,它不仅支持多种图片文件格式,而且由于使用了pinned purgeables 技术,使得大图加载过程中产生OOM的概率大大降低,对开发者来说绝对是一件喜大普奔的事情,对于像天猫HD这样需要加载大量图片的APP来说也绝对是个福音. 下载代码 首先把源码从 Git

Solr4.8.0源码分析(5)之查询流程分析总述

Solr4.8.0源码分析(5)之查询流程分析总述 前面已经写到,solr查询是通过http发送命令,solr servlet接受并进行处理.所以solr的查询流程从SolrDispatchsFilter的dofilter开始.dofilter包含了对http的各个请求的操作.Solr的查询方式有很多,比如q,fq等,本章只关注select和q.页面下发的查询请求如下:http://localhost:8080/solr/test/select?q=code%3A%E8%BE%BD*+AND+l

RxJava &amp;&amp; Agera 从源码简要分析基本调用流程(2)

版权声明:本文由晋中望原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/124 来源:腾云阁 https://www.qcloud.com/community 接上篇RxJava && Agera 从源码简要分析基本调用流程(1)我们从"1.订阅过程"."2.变换过程"进行分析,下篇文章我们继续分析"3.线程切换过程" 3.线程切换过程 从上文中我们知道了R

Fresco源码解析 - 初始化过程分析

使用Fresco之前,一定先要进行初始化,一般初始化的工作会在Application.onCreate()完成,当然也可以在使用Drawee之前完成. Fresco本身提供了两种初始化方式,一种是使用使用默认配置初始化,另一种是使用用户自定义配置. 如下代码是Fresco提供的两个初始化方法.第一个只需要提供一个Context参数,第二个还需要提供 ImagePipeline 的配置实例 - ImagePipelineConfig. /** Initializes Fresco with the

Fresco源码解析 - 创建一个ImagePipeline(一)

在Fresco源码解析 - 初始化过程分析章节中,我们分析了Fresco的初始化过程,两个initialize方法中都用到了 ImagePipelineFactory类. ImagePipelineFactory.initialize(context);会创建一个所有参数都使用默认值的ImagePipelineConfig来初始化ImagePipeline. ImagePipelineFactory.initialize(imagePipelineConfig)会首先用 imagePipelin