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

来源:互联网 发布:java ee课程设计题目 编辑:程序博客网 时间:2024/04/30 10:59

  转载请注明出处: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线程里面了,是安全的。











0 0
原创粉丝点击