Android图片加载框架Fresco分析(四)

Fresco的Model层设计

上回讲到fresco的controller层,主要涉及到的是设置请求(ImageRequest)设置动画等等。下面讲述一下fresco的第三层次,Hierarchy层。

在SimpleDraweeView的最上层DraweeView中,有一个setHierarchy(),即开发者如果需要自己定义hierarchy的话,可以使用这个方法。而如果不用自定义的话。在DraweeView的子类GenericDraweeView的构造函数中便有已经设置好的hierarchy。同样的,hierarchy也需要一个builder(GenericDraweeHierarchyBuilder)才可以创建(fresco中builder模式随处可见)。是否还记得在xml中使用SimpleDraweeView时候设置的xml各种属性?这些属性在这里才真正用到。

GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(resources);
// set fade duration
builder.setFadeDuration(fadeDuration);
// set images & scale types
if (placeholderId > 0) {
builder.setPlaceholderImage(resources.getDrawable(placeholderId), placeholderScaleType);
}
if (retryImageId > 0) {
builder.setRetryImage(resources.getDrawable(retryImageId), retryImageScaleType);
}
if (failureImageId > 0) {
builder.setFailureImage(resources.getDrawable(failureImageId), failureImageScaleType);
}
if (progressBarId > 0) {
Drawable progressBarDrawable = resources.getDrawable(progressBarId);
if (progressBarAutoRotateInterval > 0) {
progressBarDrawable =
new AutoRotateDrawable(progressBarDrawable, progressBarAutoRotateInterval);
}
builder.setProgressBarImage(progressBarDrawable, progressBarScaleType);
}
if (backgroundId > 0) {
builder.setBackground(resources.getDrawable(backgroundId));
}
if (overlayId > 0) {
builder.setOverlay(resources.getDrawable(overlayId));
}
if (pressedStateOverlayId > 0) {
builder.setPressedStateOverlay(getResources().getDrawable(pressedStateOverlayId));
}

builder.setActualImageScaleType(actualImageScaleType);
// set rounding parameters
if (roundAsCircle || roundedCornerRadius > 0) {
  RoundingParams roundingParams = new RoundingParams();
  roundingParams.setRoundAsCircle(roundAsCircle);
  if (roundedCornerRadius > 0) {
    roundingParams.setCornersRadii(
        roundTopLeft ? roundedCornerRadius : 0,
        roundTopRight ? roundedCornerRadius : 0,
        roundBottomRight ? roundedCornerRadius : 0,
        roundBottomLeft ? roundedCornerRadius : 0);
  }
  if (roundWithOverlayColor != 0) {
    roundingParams.setOverlayColor(roundWithOverlayColor);
  }
  if (roundingBorderColor != 0 && roundingBorderWidth > 0) {
    roundingParams.setBorder(roundingBorderColor, roundingBorderWidth);
  }
  builder.setRoundingParams(roundingParams);
}
setHierarchy(builder.build());

通过GenericDraweeHierarchyBuilder设置好属性之后,调用build()方法便会生成一个GenericDraweeHierarchy,那么他的图片是从哪里来的呢,GenericDraweeHierarchy实现了一个接口SettableDraweeHierarchy,这个接口中定义了图片加载过程中包括成功,失败,错误时候的情况。我们看一下成功之后的回调接口:

@Override
public void setImage(Drawable drawable, float progress, boolean immediate) {
  drawable = maybeApplyRoundingBitmapOnly(mRoundingParams, mResources, drawable);
  drawable.mutate();
  mActualImageSettableDrawable.setDrawable(drawable);
  mFadeDrawable.beginBatchMode();
  fadeOutBranches();
  fadeInLayer(mActualImageIndex);
  setProgress(progress);
  if (immediate) {
        mFadeDrawable.finishTransitionImmediately();
  }
  mFadeDrawable.endBatchMode();
}

上一段代码中就将得到的图片fadeInLayer,而其他站位图则都进行了fadeOut,所以此时getTopDrawable时,便是获取到的最新的图片。那么又是什么时候去获取的图片呢。这时候需要回去看一下在AbstractDraweeController(用来控制图片显示的)中的Hierarchy便是直接使用的SettableDraweeHierarchy,也就是说,Controller中已经持有了SettableDraweeHierarchy的一个实例。

@Override
  public @Nullable
  DraweeHierarchy getHierarchy() {
return mSettableDraweeHierarchy;
  }

之后的就是上一篇文章中提到的,在AbstractDraweeController中如果发请求的话,会调用到submitRequest()方法,在此方法中会开线程去下载图片,如果图片下载成功回调至onNewResultImpl()方法中,紧接着又会执行到onNewResultInternal()方法中,这个方法中就会有这样一句:

mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate);

此时之前的SimpleDraweeView中的Hierarvhy便有了真正的图片,而之前在显示的时候都是占位图,此时再获取的时候就会发现,topDrawable便开始有了真正的图片可以显示。这样整个图片从请求到请求完成,到如何显示的流程便分析完成了。