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