Fresco:SimpleDraweeView如何显示并加载图片

来源:互联网 发布:python sleep函数 编辑:程序博客网 时间:2024/05/17 23:42

使用Fresco, 如果仅仅是想简单下载一张网络图片,在下载完成之前,显示一张占位图,那么简单使用 SimpleDraweeView 即可。那么SimpleDraweeView是如何如何显示并加载图片呢?

我们知道在使用Fresco前,需要调用

Fresco.initialize(context);

Fresco.initialize做哪些工作

该函数有两个实现:

/** Initializes Fresco with the default config. */public static void initialize(Context context) {  ImagePipelineFactory.initialize(context);  initializeDrawee(context);}/** Initializes Fresco with the specified config. */public static void initialize(Context context, ImagePipelineConfig imagePipelineConfig) {  ImagePipelineFactory.initialize(imagePipelineConfig);  initializeDrawee(context);}

第一个无需配置ImagePipelineConfig,这种情况下使用默认配置。会构造一个只包含mContext值的ImagePipelineConfig对象,该对象中其他成员变量为空。

该函数主要做两件事,第一初始化ImagePipelineFactory,第二初始化Drawee:将使用配置的ImagePipelineConfig(默认的,或使用自定义参数的)构造的ImagePipeline赋值给Fresco的静态成员变量sDraweeControllerBuilderSupplier 的成员变量mImagePipeline.

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

然后使用sDraweeControllerBuilderSupplier初始化SimpleDraweeView。sDraweeControllerBuilderSupplier的类型为:
public class PipelineDraweeControllerBuilderSupplier implements
Supplier

SimpleDraweeView的构造函数

SimpleDraweeView的构造函数会调用init()函数,该函数会初始化成员变量mSimpleDraweeControllerBuilder ,类型为:SimpleDraweeControllerBuilder。

private void init() {  if (isInEditMode()) {    return;  }  Preconditions.checkNotNull(      sDraweeControllerBuilderSupplier,      "SimpleDraweeView was not initialized!");  mSimpleDraweeControllerBuilder = sDraweeControllerBuilderSupplier.get();}

sDraweeControllerBuilderSupplier.get()返回PipelineDraweeControllerBuilder类型的数据,该类继承AbstractDraweeControllerBuilder类,后者继承了SimpleDraweeControllerBuilder接口。

@Overridepublic PipelineDraweeControllerBuilder get() {  return new PipelineDraweeControllerBuilder(      mContext,      mPipelineDraweeControllerFactory,      mImagePipeline,      mBoundControllerListeners);}

SimpleDraweeView::setImageURI()

我们通过setImageURI为调用SimpleDraweeView设置图片,
该函数分两部分,第一创建DraweeController ,第二设置Controller.

创建DraweeController

通过调用mSimpleDraweeControllerBuilder的build()函数实现,代码如下:

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

即调用drawee\src\main\java\com\facebook\drawee\controller\AbstractDraweeControllerBuilder.java 的build():

/** Builds the specified controller. */@Overridepublic AbstractDraweeController build() {  validate();  // if only a low-res request is specified, treat it as a final request.  if (mImageRequest == null && mMultiImageRequests == null && mLowResImageRequest != null) {    mImageRequest = mLowResImageRequest;    mLowResImageRequest = null;  }  return buildController();}/** Builds a regular controller. */protected AbstractDraweeController buildController() {  AbstractDraweeController controller = obtainController();  controller.setRetainImageOnFailure(getRetainImageOnFailure());  maybeBuildAndSetRetryManager(controller);  maybeAttachListeners(controller);  return controller;}

obtainController()的实现在PipelineDraweeControllerBuilder.java中:

@Overrideprotected PipelineDraweeController obtainController() {  DraweeController oldController = getOldController();  PipelineDraweeController controller;  if (oldController instanceof PipelineDraweeController) {    controller = (PipelineDraweeController) oldController;    controller.initialize(        obtainDataSourceSupplier(),        generateUniqueControllerId(),        getCallerContext());  } else {    controller = mPipelineDraweeControllerFactory.newController(        obtainDataSourceSupplier(),        generateUniqueControllerId(),        getCallerContext());  }  return controller;}

调用AbstractDraweeControllerBuilder.java的obtainDataSourceSupplier():

/** Gets the top-level data source supplier to be used by a controller. */protected Supplier<DataSource<IMAGE>> obtainDataSourceSupplier() {  if (mDataSourceSupplier != null) {    return mDataSourceSupplier;  }  Supplier<DataSource<IMAGE>> supplier = null;  // final image supplier;  if (mImageRequest != null) {    supplier = getDataSourceSupplierForRequest(mImageRequest);  } else if (mMultiImageRequests != null) {    supplier = getFirstAvailableDataSourceSupplier(mMultiImageRequests, mTryCacheOnlyFirst);  }  // increasing-quality supplier; highest-quality supplier goes first  if (supplier != null && mLowResImageRequest != null) {    List<Supplier<DataSource<IMAGE>>> suppliers = new ArrayList<>(2);    suppliers.add(supplier);    suppliers.add(getDataSourceSupplierForRequest(mLowResImageRequest));    supplier = IncreasingQualityDataSourceSupplier.create(suppliers);  }  // no image requests; use null data source supplier  if (supplier == null) {    supplier = DataSources.getFailedDataSourceSupplier(NO_REQUEST_EXCEPTION);  }  return supplier;}/** Creates a data source supplier for the given image request. */protected Supplier<DataSource<IMAGE>> getDataSourceSupplierForRequest(    final REQUEST imageRequest,    final boolean bitmapCacheOnly) {  final Object callerContext = getCallerContext();  return new Supplier<DataSource<IMAGE>>() {    @Override    public DataSource<IMAGE> get() {      return getDataSourceForRequest(imageRequest, callerContext, bitmapCacheOnly);    }    @Override    public String toString() {      return Objects.toStringHelper(this)          .add("request", imageRequest.toString())          .toString();    }  };}

最后通过PipelineDraweeControllerBuilder.java的getDataSourceForRequest()返回DataSourceSupplier。该DataSourceSupplier的get()会调用getDataSourceForRequest()将获取到的图片数据返回,返回数据类型为:DataSource

@Overrideprotected DataSource<CloseableReference<CloseableImage>> getDataSourceForRequest(    ImageRequest imageRequest,    Object callerContext,    boolean bitmapCacheOnly) {  if (bitmapCacheOnly) {    return mImagePipeline.fetchImageFromBitmapCache(imageRequest, callerContext);  } else {    return mImagePipeline.fetchDecodedImage(imageRequest, callerContext);  }}

设置Controller

接着回到 setImageURI函数中的 setController(controller)的实现:

  /** Sets the controller. */  public void setController(@Nullable DraweeController draweeController) {    mDraweeHolder.setController(draweeController);    super.setImageDrawable(mDraweeHolder.getTopLevelDrawable());  }

调用DraweeHolder.java的setController()函数:

 /**   * Sets a new controller.   */  public void setController(@Nullable DraweeController draweeController) {    boolean wasAttached = mIsControllerAttached;    if (wasAttached) {      detachController();    }    // Clear the old controller    if (mController != null) {      mEventTracker.recordEvent(Event.ON_CLEAR_OLD_CONTROLLER);      mController.setHierarchy(null);    }    mController = draweeController;    if (mController != null) {      mEventTracker.recordEvent(Event.ON_SET_CONTROLLER);      mController.setHierarchy(mHierarchy);    } else {      mEventTracker.recordEvent(Event.ON_CLEAR_CONTROLLER);    }    if (wasAttached) {      attachController();    }  }

该函数主要的功能是调用mController.setHierarchy(mHierarchy);关于mHierarchy,是在SimpleDraweeView的父类GenericDraweeView的构造函数中设置的:

   protected void inflateHierarchy(Context context, @Nullable AttributeSet attrs) {    GenericDraweeHierarchyBuilder builder =        GenericDraweeHierarchyInflater.inflateBuilder(context, attrs);    setAspectRatio(builder.getDesiredAspectRatio());    setHierarchy(builder.build());  }

根据我们在XML中声明的SimpleDraweeView的一些属性创建GenericDraweeHierarchyBuilder,然后调用它的build()函数生成GenericDraweeHierarchy:

  /**   * 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;  }    

再返回setController(controller)中,可以看到调用 super.setImageDrawable(mDraweeHolder.getTopLevelDrawable()),即ImageView的setImageDrawable函数,让图片在SimpleDraweeView中显示。

GenericDraweeHierarchy

这是Fresco的特点,每个SimpleDraweeView设置的图片都是RootDrawable类型的,对应GenericDraweeHierarchy的mTopLevelDrawable成员变量,而GenericDraweeHierarchy是类似下图的hierachy:

   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)

在该类的构造函数中我们可以看到对上述各层图片的创建过程:

GenericDraweeHierarchy(GenericDraweeHierarchyBuilder builder) {    mResources = builder.getResources();    mRoundingParams = builder.getRoundingParams();    mActualImageWrapper = new ForwardingDrawable(mEmptyActualImageDrawable);    int numBackgrounds = (builder.getBackgrounds() != null) ? builder.getBackgrounds().size() : 0;    int numOverlays = (builder.getOverlays() != null) ? builder.getOverlays().size() : 0;    numOverlays += (builder.getPressedStateOverlay() != null) ? 1 : 0;    // layer indices and count    int numLayers = 0;    int backgroundsIndex = numLayers;    numLayers += numBackgrounds;    mPlaceholderImageIndex = numLayers++;    mActualImageIndex = numLayers++;    mProgressBarImageIndex = numLayers++;    mRetryImageIndex = numLayers++;    mFailureImageIndex = numLayers++;    int overlaysIndex = numLayers;    numLayers += numOverlays;    // array of layers    Drawable[] layers = new Drawable[numLayers];    if (numBackgrounds > 0) {      int index = 0;      for (Drawable background : builder.getBackgrounds()) {        layers[backgroundsIndex + index++] = buildBranch(background, null);      }    }    layers[mPlaceholderImageIndex] = buildBranch(        builder.getPlaceholderImage(),        builder.getPlaceholderImageScaleType());    layers[mActualImageIndex] = buildActualImageBranch(        mActualImageWrapper,        builder.getActualImageScaleType(),        builder.getActualImageFocusPoint(),        builder.getActualImageMatrix(),        builder.getActualImageColorFilter());    layers[mProgressBarImageIndex] = buildBranch(        builder.getProgressBarImage(),        builder.getProgressBarImageScaleType());    layers[mRetryImageIndex] = buildBranch(        builder.getRetryImage(),        builder.getRetryImageScaleType());    layers[mFailureImageIndex] = buildBranch(        builder.getFailureImage(),        builder.getFailureImageScaleType());    if (numOverlays > 0) {      int index = 0;      if (builder.getOverlays() != null) {        for (Drawable overlay : builder.getOverlays()) {          layers[overlaysIndex + index++] = buildBranch(overlay, null);        }      }      if (builder.getPressedStateOverlay() != null) {        layers[overlaysIndex + 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();  }

在获取到图片后,只需调用该类的setImage()函数将图片设置给mActualImageWrapper即可:

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

上述设置图片的过程是在com/facebook/drawee/controller/AbstractDraweeController.java中定义的:

protected void submitRequest() {    ...    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();            float progress = dataSource.getProgress();            T image = dataSource.getResult();            if (image != null) {              onNewResultInternal(id, dataSource, image, progress, isFinished, wasImmediate);            } else if (isFinished) {              onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true);            }          }         ...  }  private void onNewResultInternal(      String id,      DataSource<T> dataSource,      @Nullable T image,      float progress,      boolean isFinished,      boolean wasImmediate) {   ...    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;        mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate);        getControllerListener().onFinalImageSet(id, getImageInfo(image), getAnimatable());        // IMPORTANT: do not execute any instance-specific code after this point...  }

其中mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate);将图片设置到SimpleDraweeView对应的DraweeHierarchy中。

0 0
原创粉丝点击