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中。
- Fresco:SimpleDraweeView如何显示并加载图片
- Fresco、SimpleDraweeView加载资源文件
- Fresco SimpleDraweeView 加载本地的gif
- Fresco图片加载库的使用(SimpleDraweeView的简单使用 )
- MVP实现用Retrofit请求网络数据Fresco加载图片,Recyclerview CheckBox显示并实现全选删除
- fresco 加载本地路径图片,并修改图片尺寸
- Fresco 使用笔记(一):加载gif图片并播放
- Fresco 使用笔记(一):加载gif图片并播放
- fresco 加载本地路径图片,并修改图片尺寸
- Fresco 加载本地图片
- Fresco图片加载组件
- 图片加载Fresco
- 使用Fresco加载图片
- 图片加载利器--Fresco
- Fresco图片加载工具
- 图片加载库Fresco
- fresco加载本地图片
- 使用Fresco加载图片
- jquery 动态实现进度条
- Windows安装多个mysql数据库
- li标签中,img居中显示
- 《JavaScript详解》学习笔记
- Merge Two Sorted Lists 归并list
- Fresco:SimpleDraweeView如何显示并加载图片
- Zend Framework 2.0的Mvc结构及启动流程分析
- 排序--快速排序
- 漫谈Java加密技术(四)
- 吉他指板上音符的几个把位
- 排序和顺序统计量
- 欢迎使用CSDN-markdown编辑器
- XML总结
- 结构和其他数据形式