文章将会被同步至微信公众号:Android部落格

流程图如下:
Android-Fresco系列2 加载资源_第1张图片

一、SimpleDraweeView加载图片

val draweeView = findViewById<SimpleDraweeView>(R.id.my_image_view)draweeView.setImageURI("http://ww1.sinaimg.cn/large/610dc034ly1fjaxhky81vj20u00u0ta1.jpg")

通过setImageURI函数设置图片加载,参数是Uri参数或图片地址。

1) setImageURI

//SimpleDraweeViewpublic void setImageURI(Uri uri, @Nullable Object callerContext) {    DraweeController controller =        mControllerBuilder            .setCallerContext(callerContext)            .setUri(uri)            .setOldController(getController())            .build();    setController(controller);}

从这个方法开始了图片加载之旅。比较重要的是两个类PipelineDraweeControllerBuilder,AbstractDraweeControllerBuilder,前者继承自后者。

2) PipelineDraweeControllerBuilder

  • callerContext参数默认为null。
  • mControllerBuilder对象在SimpleDraweeView的init方法中初始化。
  • setUri在PipelineDraweeControllerBuilder类中
//PipelineDraweeControllerBuilder@Overridepublic PipelineDraweeControllerBuilder setUri(@Nullable Uri uri) {    if (uri == null) {      return super.setImageRequest(null);    }    ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(uri)        .setRotationOptions(RotationOptions.autoRotateAtRenderTime())        .build();    return super.setImageRequest(imageRequest);}

3) ImageRequest

ImageRequestBuilder类构建了一个ImageRequest对象,build方法是:

//ImageRequestBuilderpublic ImageRequest build() {    validate();    return new ImageRequest(this);}

validate用于检查图片地址。

ImageRequest构造函数主要初始化了以下参数:

mCacheChoice//缓存选择mSourceUri//地址mSourceUriType//地址类型,网络,本地,asset,resourcemProgressiveRenderingEnabled//进度渲染是否允许mLocalThumbnailPreviewsEnabled//本地略缩图预览是否允许mImageDecodeOptions//图片解码选项mResizeOptions//裁剪mRotationOptions//旋转mIsDiskCacheEnabled//磁盘缓存mIsMemoryCacheEnabled//内存缓存...

4) AbstractDraweeControllerBuilder

最后还要调用一下父类AbstractDraweeControllerBuilder的setImageRequest方法,初始化以下mImageRequest对象:

//AbstractDraweeControllerBuilderpublic BUILDER setImageRequest(REQUEST imageRequest) {    mImageRequest = imageRequest;    return getThis();}
  • setOldController

getController方法先获取一下前一个Controller,然后设置到AbstractDraweeControllerBuilder类中。

  • build

定义在AbstractDraweeControllerBuilder类中:

//AbstractDraweeControllerBuilder@Overridepublic AbstractDraweeController build() {    return buildController();}//AbstractDraweeControllerBuilderprotected AbstractDraweeController buildController() {    AbstractDraweeController controller = obtainController();    return controller;}

5) PipelineDraweeControllerBuilder

  • obtainController

obtainController方法定义在PipelineDraweeControllerBuilder类中:

//PipelineDraweeControllerBuilder@Overrideprotected PipelineDraweeController obtainController() {    try {      DraweeController oldController = getOldController();      PipelineDraweeController controller;      final String controllerId = generateUniqueControllerId();      if (oldController instanceof PipelineDraweeController) {        controller = (PipelineDraweeController) oldController;      } else {        controller = mPipelineDraweeControllerFactory.newController();      }      controller.initialize(          obtainDataSourceSupplier(controller, controllerId),          controllerId,          getCacheKey(),          getCallerContext(),          mCustomDrawableFactories,          mImageOriginListener);      return controller;    } finally {    }}

设置Controller的时候,先判断前一个controller是否存在,存在的话获取旧的,并强转成PipelineDraweeController类型,否则新建一个。

6) PipelineDraweeControllerFactory

  • newController

一般情况下,第一次加载都是新建:

//PipelineDraweeControllerFactorypublic PipelineDraweeController newController() {    PipelineDraweeController controller =        internalCreateController(            mResources,            mDeferredReleaser,            mAnimatedDrawableFactory,            mUiThreadExecutor,            mMemoryCache,            mDrawableFactories);    return controller;}protected PipelineDraweeController internalCreateController() {    return new PipelineDraweeController(        resources,        deferredReleaser,        animatedDrawableFactory,        uiThreadExecutor,        memoryCache,        drawableFactories);}

最终返回一个PipelineDraweeController对象。然后执行对象的initialize方法,在执行这个方法之前,里面有一个参数是通过obtainDataSourceSupplier方法获取的,另外一个是getCacheKey,先看看这两个方法再(这个方法涉及的流程比较长,删除部分不关心的代码):

  • obtainDataSourceSupplier
//AbstractDraweeControllerBuilderprotected Supplier<DataSource<IMAGE>> obtainDataSourceSupplier(  final DraweeController controller, final String controllerId) {    Supplier<DataSource<IMAGE>> supplier = null;        // final image supplier;    if (mImageRequest != null) {      supplier = getDataSourceSupplierForRequest(controller, controllerId, mImageRequest);    } else if (mMultiImageRequests != null) {      supplier = getFirstAvailableDataSourceSupplier(              controller, controllerId, mMultiImageRequests, mTryCacheOnlyFirst);    }    return supplier;}

即使走getFirstAvailableDataSourceSupplier分支,也会调用getDataSourceSupplierForRequest方法,看看这个方法:

  • getDataSourceSupplierForRequest
//AbstractDraweeControllerBuilder/** Creates a data source supplier for the given image request. */protected Supplier<DataSource<IMAGE>> getDataSourceSupplierForRequest(  final DraweeController controller,  final String controllerId,  final REQUEST imageRequest,  final CacheLevel cacheLevel) {    final Object callerContext = getCallerContext();    return new Supplier<DataSource<IMAGE>>() {      @Override      public DataSource<IMAGE> get() {        return getDataSourceForRequest(            controller, controllerId, imageRequest, callerContext, cacheLevel);      }          @Override      public String toString() {        return Objects.toStringHelper(this).add("request", imageRequest.toString()).toString();      }    };}

到这里可以缓一缓,因为返回了一个Supplier对象,而且新建这个对象的时候在实现get方法的时候返回了一个getDataSourceForRequest方法,这个方法在PipelineDraweeControllerBuilder类中定义,先不看。

  • getCacheKey
    获取缓存key。
//PipelineDraweeControllerBuilderprivate @Nullable CacheKey getCacheKey() {    final ImageRequest imageRequest = getImageRequest();    final CacheKeyFactory cacheKeyFactory = mImagePipeline.getCacheKeyFactory();    CacheKey cacheKey = null;    if (cacheKeyFactory != null && imageRequest != null) {      if (imageRequest.getPostprocessor() != null) {        cacheKey = cacheKeyFactory.getPostprocessedBitmapCacheKey(            imageRequest,            getCallerContext());      } else {        cacheKey = cacheKeyFactory.getBitmapCacheKey(            imageRequest,            getCallerContext());      }    }    return cacheKey;}

cacheKeyFactory的初始化是在ImagePipelineConfig的构造函数中:

//ImagePipelineConfigmCacheKeyFactory = builder.mCacheKeyFactory == null        ? DefaultCacheKeyFactory.getInstance()        : builder.mCacheKeyFactory;

看看DefaultCacheKeyFactory类中怎么返回缓存key的:

//DefaultCacheKeyFactory@Overridepublic CacheKey getBitmapCacheKey(ImageRequest request, Object callerContext) {    return new BitmapMemoryCacheKey(        getCacheKeySourceUri(request.getSourceUri()).toString(),        request.getResizeOptions(),        request.getRotationOptions(),        request.getImageDecodeOptions(),        null,        null,        callerContext);}

其实是返回一个BitmapMemoryCacheKey对象,这个对象继承自CacheKey。

回到obtainController方法中调用的initialize方法,再看看:

//PipelineDraweeControllerpublic void initialize(  Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,  String id,  CacheKey cacheKey,  Object callerContext,  @Nullable ImmutableList<DrawableFactory> customDrawableFactories,  @Nullable ImageOriginListener imageOriginListener) {    super.initialize(id, callerContext);    mDataSourceSupplier = dataSourceSupplier;    mCacheKey = cacheKey;}

主要初始化了几个对象。

获取controller对象完毕之后,就开始执行setController方法:

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

DraweeHolder中定义了setController方法:

//DraweeHolderpublic void setController(@Nullable DraweeController draweeController) {    boolean wasAttached = mIsControllerAttached;    if (wasAttached) {      detachController();    }        // Clear the old controller    if (isControllerValid()) {      mController.setHierarchy(null);    }    mController = draweeController;    if (mController != null) {      mController.setHierarchy(mHierarchy);    } else {    }        if (wasAttached) {      attachController();    }}

二、视图可见性发生变化

可以看到此时wasAttached为false,这样一来detachController和attachController方法都无法调用了,调用栈流程到这里仿佛中断了。

1) GenericDraweeView

记得在GenericDraweeView在构造函数中会执行inflateHierarchy方法:

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

2) DraweeHolder

重新看看setHierarchy,最终调用到DraweeHolder的setHierarchy方法:

//DraweeHolderpublic void setHierarchy(DH hierarchy) {    mEventTracker.recordEvent(Event.ON_SET_HIERARCHY);    final boolean isControllerValid = isControllerValid();    setVisibilityCallback(null);    mHierarchy = Preconditions.checkNotNull(hierarchy);    Drawable drawable = mHierarchy.getTopLevelDrawable();    onVisibilityChange(drawable == null || drawable.isVisible());    setVisibilityCallback(this);    if (isControllerValid) {      mController.setHierarchy(hierarchy);    }}

这里有一个setVisibilityCallback方法,设置了visiable监听:

//DraweeHolderprivate void setVisibilityCallback(@Nullable VisibilityCallback visibilityCallback) {    Drawable drawable = getTopLevelDrawable();    if (drawable instanceof VisibilityAwareDrawable) {      ((VisibilityAwareDrawable) drawable).setVisibilityCallback(visibilityCallback);    }}

getTopLevelDrawable方法获取的是mHierarchy对象的Drawable,而mHierarchy方法对应GenericDraweeHierarchy类,这个类里面的getTopLevelDrawable方法对应的是RootDrawable,它继承自ForwardingDrawable类,它又继承自Android原生Drawable。所以实际上是设置了Drawable可见性监听。当收到可见性变化时,先在ForwardingDrawable接收到回调信号:

//ForwardingDrawable@Overridepublic boolean setVisible(boolean visible, boolean restart) {    final boolean superResult = super.setVisible(visible, restart);    if (mCurrentDelegate == null) {      return superResult;    }    return mCurrentDelegate.setVisible(visible, restart); }

mCurrentDelegate是RootDrawable:

//RootDrawable@Overridepublic boolean setVisible(boolean visible, boolean restart) {    if (mVisibilityCallback != null) {      mVisibilityCallback.onVisibilityChange(visible);    }    return super.setVisible(visible, restart);}

终于看到回调方法的地方了,刚才说到DraweeHolder设置了监听,那么在DraweeHolder中看看回调逻辑:

//DraweeHolder@Overridepublic void onVisibilityChange(boolean isVisible) {    mIsVisible = isVisible;    attachOrDetachController();}//DraweeHolderprivate void attachOrDetachController() {    if (mIsHolderAttached && mIsVisible) {      attachController();    } else {      detachController();    }}

如果holder没有附属到view上时,将其连接上,否则剥离掉。
先看看attachController函数:

  • attachController
if (mController != null && mController.getHierarchy() != null) {  mController.onAttach();}

开始在Controller类中执行onAttach方法,这个方法实现在AbstractDraweeController类中,定义在DraweeController接口中。

//AbstractDraweeController@Override public void onAttach() {  if (!mIsRequestSubmitted) {      submitRequest();    }}

核心方法就两行代码,提交刚才的请求:

//AbstractDraweeControllerprotected void submitRequest() {    final T closeableImage = getCachedImage();    if (closeableImage != null) {        onImageLoadedFromCacheImmediately(mId, closeableImage);        onNewResultInternal(mId, mDataSource, closeableImage, 1.0f, true, true, true);        return;    }    mSettableDraweeHierarchy.setProgress(0, true);    mIsRequestSubmitted = true;    mHasFetchFailed = false;    mDataSource = getDataSource();    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();            boolean hasMultipleResults = dataSource.hasMultipleResults();            float progress = dataSource.getProgress();            T image = dataSource.getResult();            if (image != null) {              onNewResultInternal(                  id, dataSource, image, progress, isFinished, wasImmediate, hasMultipleResults);            } else if (isFinished) {              onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true);            }          }          @Override          public void onFailureImpl(DataSource<T> dataSource) {            onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true);          }          @Override          public void onProgressUpdate(DataSource<T> dataSource) {            boolean isFinished = dataSource.isFinished();            float progress = dataSource.getProgress();            onProgressUpdateInternal(id, dataSource, progress, isFinished);          }        };    mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor);}

这个方法里面是核心的代码,分为两个部分,前一个部分是找本地缓存,有缓存的话,直接取缓存数据展示然后返回,否则就去请求并加载。

3) 取内存缓存

先看取缓存,getCachedImage:

//PipelineDraweeController  @Override  protected @Nullable CloseableReference<CloseableImage> getCachedImage() {    try {      if (mMemoryCache == null || mCacheKey == null) {        return null;      }      // We get the CacheKey      CloseableReference<CloseableImage> closeableImage = mMemoryCache.get(mCacheKey);      if (closeableImage != null && !closeableImage.get().getQualityInfo().isOfFullQuality()) {        closeableImage.close();        return null;      }      return closeableImage;    } finally {    }}

从内存缓存中取数据,是CloseableImage类型的,取到缓存并符合质量条件就返回,对于不符合质量条件的关闭closeableImage并返回null,关闭的过程实际是在一个SharedReference对象中将CloseableImage对象的引用计数删除或计数减一。
后续单独讲缓存策略。

获取到缓存之后,执行onImageLoadedFromCacheImmediately通知消息注册者,从内存取到缓存数据了。

4) 显示内存缓存图片

onNewResultInternal才是真正加载图片的地方:

//AbstractDraweeControllerprivate void onNewResultInternal(      String id,      DataSource<T> dataSource,      @Nullable T image,      float progress,      boolean isFinished,      boolean wasImmediate,      boolean deliverTempResult) {    try {        Drawable drawable;        try {            drawable = createDrawable(image);        } catch (Exception exception) {        }        try {            // set the new image            if (isFinished) {                mDataSource = null;               mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate);            }        } finally {            releaseDrawable(previousDrawable);        }    } finally {    }}

先看看createDrawable的代码:

//PipelineDraweeController@Overrideprotected Drawable createDrawable(CloseableReference<CloseableImage> image) {    drawable = mDefaultDrawableFactory.createDrawable(closeableImage);    if (drawable != null) {        return drawable;    }}//DefaultDrawableFactory@Override@Nullablepublic Drawable createDrawable(CloseableImage closeableImage) {    try {        if (closeableImage instanceof CloseableStaticBitmap) {            CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) closeableImage;            Drawable bitmapDrawable = new BitmapDrawable(mResources, closeableStaticBitmap.getUnderlyingBitmap());            if (!hasTransformableRotationAngle(closeableStaticBitmap)                && !hasTransformableExifOrientation(closeableStaticBitmap)) {              // Return the bitmap drawable directly as there's nothing to transform in it                return bitmapDrawable;            }        }    } finally {    }}

在createDrawable方法中,将获取到的缓存数据强转成CloseableStaticBitmap对象并执行getUnderlyingBitmap方法返回,实际就是就是一个Bitmap对象,再将其封装到BitmapDrawable对象,然后展示。

setImage最终调用在GenericDraweeHierarchy中:

//AbstractDraweeControllermSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate);//GenericDraweeHierarchy@Overridepublic void setImage(Drawable drawable, float progress, boolean immediate) {    drawable = WrappingUtils.maybeApplyLeafRounding(drawable, mRoundingParams, mResources);    drawable.mutate();    mActualImageWrapper.setDrawable(drawable);    mFadeDrawable.beginBatchMode();    fadeOutBranches();    fadeInLayer(ACTUAL_IMAGE_INDEX);    setProgress(progress);    if (immediate) {      mFadeDrawable.finishTransitionImmediately();    }    mFadeDrawable.endBatchMode();}

先看看有没有圆角参数需要设置,然后设置真正的位图,再渐变,设置进度,最后将刷新参数减一并统一刷新视图。

从attachController方法到现在只是讲了从缓存读取数据并展示,下面将以在线图片为例看看怎么加载图片的。

微信公众号二维码:

更多相关文章

  1. Android 几种加密解密的方法(仅代码)
  2. Android 实现模拟按键方法一
  3. Android两种轮询的实现方法
  4. Android MonkeyRunner调用方法总结
  5. android home 键的监听方法记录
  6. Android 四种获取屏幕宽度的方法总结
  7. JAVA如何判断对象的类型

随机推荐

  1. Android之LinearLayout线性布局
  2. android学习
  3. Android之UI学习篇五:AutoCompleteTextVie
  4. Android(安卓)操作串口 (android serial
  5. 想抢先体验Android操作系统的魅力吗?那就
  6. 想抢先体验Android操作系统的魅力吗?那就
  7. 【Android(安卓)设计】:样式_ 触感 | 度量
  8. android开发 - 圆角和边框
  9. 屏蔽电信流氓广告造成的诡异的问题--Andr
  10. 基于android的智能家居之一MJPGstream