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

Fresco的View层设计

Fresco的view层较为简单,主要有三个view,DraweeView <– GenericDraweeView <– SimpleDraweeView,这便是View层控件的继承关系。在这三个view中,如果需要简单使用的话,可以直接使用SimpleDraweeView,如果要自定义View的话也可以继承上层的两个view。GenericDraweeView中则包含了很重要的用来显示图片的Hierarchy类,而最上层的DraweeView则包含了控制图片展示的Controller。下面将对每个view进行分析。

###1.DraweeView

DraweeView虽然是用来加载图片的,而且也是继承自ImageView,但是Facebook并不支持使用ImageView内部的一些方法。之后的Fresco方法会摒弃ImageView,改继承自View。

DraweeView初始化的时候会得到一个DraweeHolder对象,而DraweeHolder对于DraweeView便是类似于一个管家,DraweeView将内部需要的大部分事情都交给了Holder来负责管理。比如setHierarchy()和setController()方法,都是将内容交给了holder来管理。这也是一个很好的分层管理方式,值得借鉴。

在DraweeView类中,Fresco提供了PipelineDraweeController,即pipeline机制来控制整个图片的缓存下载和显示逻辑。也可以通过自定义Controller设置加载图片。

###2.GenericDraweeView

在DraweeView的子类GenericDraweeView中,作者自定义了attrs属性。意味着,使用者只要在XML文件中针对View使用相应的属性参数便可以达到设置Hierarchy的属性。这样就方便了使用者,只要在XML中就可以得到自己想要的动画以及图片展示效果。

DraweeView that creates GenericDraweeHierarchy based on XML attributes.

下面列出了GenericDraweeView其中包含了Hierarchy中可以设置的很多属性:

/* Fading animation parameters:
 * @attr ref com.facebook.R.styleable#GenericDraweeView_fadeDuration
 * Images & scale types parameters:
 * @attr ref com.facebook.R.styleable#GenericDraweeView_viewAspectRatio
 * @attr ref com.facebook.R.styleable#GenericDraweeView_placeholderImage
 * @attr ref com.facebook.R.styleable#GenericDraweeView_placeholderImageScaleType
 * @attr ref com.facebook.R.styleable#GenericDraweeView_retryImage
 * @attr ref com.facebook.R.styleable#GenericDraweeView_retryImageScaleType
 * @attr ref com.facebook.R.styleable#GenericDraweeView_failureImage
 * @attr ref com.facebook.R.styleable#GenericDraweeView_failureImageScaleType
 * @attr ref com.facebook.R.styleable#GenericDraweeView_progressBarImage
 * @attr ref com.facebook.R.styleable#GenericDraweeView_progressBarImageScaleType
 * @attr ref com.facebook.R.styleable#GenericDraweeView_progressBarAutoRotateInterval
 * @attr ref com.facebook.R.styleable#GenericDraweeView_actualImageScaleType
 * @attr ref com.facebook.R.styleable#GenericDraweeView_backgroundImage
 * @attr ref com.facebook.R.styleable#GenericDraweeView_overlayImage
 * @attr ref com.facebook.R.styleable#GenericDraweeView_pressedStateOverlayImage
 * Rounding parameters:
 * @attr ref com.facebook.R.styleable#GenericDraweeView_roundAsCircle
 * @attr ref com.facebook.R.styleable#GenericDraweeView_roundedCornerRadius
 * @attr ref com.facebook.R.styleable#GenericDraweeView_roundTopLeft
 * @attr ref com.facebook.R.styleable#GenericDraweeView_roundTopRight
 * @attr ref com.facebook.R.styleable#GenericDraweeView_roundBottomRight
 * @attr ref com.facebook.R.styleable#GenericDraweeView_roundBottomLeft
 * @attr ref com.facebook.R.styleable#GenericDraweeView_roundWithOverlayColor
 * @attr ref com.facebook.R.styleable#GenericDraweeView_roundingBorderWidth
 * @attr ref com.facebook.R.styleable#GenericDraweeView_roundingBorderColor
 */

GenericDraweeView中属性设置的部分和一般自定义控件类似:

TypedArray gdhAttrs = context.obtainStyledAttributes(
      attrs,
      R.styleable.GenericDraweeView);
fadeDuration = gdhAttrs.getInt(
        R.styleable.GenericDraweeView_fadeDuration,
        fadeDuration);

在完成这些设置之后,GenericDraweeView 需要一个GenericDraweeHierarchyBuilder类的对象来保存所有的属性值,而他的返回值便是一个Hierarchy。也就是说,通过Builder的build()方法,构造了一个View需要的Hierarchy,然后把XML中设置的属性都保存在Builder中等待使用。

GenericDraweeHierarchyBuilder builder = new GenericDraweeHierarchyBuilder(resources);
builder.setFadeDuration(fadeDuration);
...其余属性设置
setHierarchy(builder.build());

Fresco在使用DraweeView的时候虽然宽高不能设置wrap_content,但是它提供了一个可以动态设置宽高比例的方法setAspectRatio,因此它需要在GenericDraweeView的OnMeasure方法中重新设置宽高

private final AspectRatioMeasure.Spec mMeasureSpec = new AspectRatioMeasure.Spec();
    @Override
      protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
    mMeasureSpec.width = widthMeasureSpec;
    mMeasureSpec.height = heightMeasureSpec;
    AspectRatioMeasure.updateMeasureSpec(
        mMeasureSpec,
        mAspectRatio,
        getLayoutParams(),
        getPaddingLeft() + getPaddingRight(),
        getPaddingTop() + getPaddingBottom());
    super.onMeasure(mMeasureSpec.width, mMeasureSpec.height);
  }

AspectRatioMeasure类中的updateMeasureSpec方法,便是通过比例给View重新设置宽高。

###3.SimpleDraweeView
SimpleDraweeView类中有个静态的初始化方法initialize,这个初始化方法会在Fresco的
initialize中调用。

public static void initialize(Context context, ImagePipelineConfig imagePipelineConfig) {
  ImagePipelineFactory.initialize(imagePipelineConfig);
  initializeDrawee(context);
}

private static void initializeDrawee(Context context) {
  sDraweeControllerBuilderSupplier = new PipelineDraweeControllerBuilderSupplier(context);
  SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);
}

其实说白了就是Fresco在初始化的时候会new一个controller(PipelineDraweeControllerBuilderSupplier类的对象),而这个controller,每个SimpleDraweeView都可以使用。SimpleDraweeView中其他的方法也都是复写的父类的方法。便不再一一叙述。