Fresco图片框架实现原理(二):DraweeController

接上文《Fresco图片框架实现原理(一)》文末

private static void initializeDrawee(
      Context context,
      @Nullable DraweeConfig draweeConfig) {
    sDraweeControllerBuilderSupplier =
        new PipelineDraweeControllerBuilderSupplier(context, draweeConfig);
    SimpleDraweeView.initialize(sDraweeControllerBuilderSupplier);  }

在研究正真的PipelineDraweeController之前,先来看看PipelineDraweeControllerBuilder在Fresco中的构造原理和过程

从上面的函数我们一个一个往里面点

image.png

PipelineDraweeControllerBuilderSupplier是一个提供者模式,主要是为了构造PipelineDraweeControllerBuilder类
图像管道Drawee contrller builder的具体实现类
PipelineDraweeControllerBuilder.png

AbstractDraweeControllerBuilder.png

SimpleDraweeControllerBuilder接口.png

这下继承关系清除了:


继承关系图.png

SimpleDraweeControllerBuilder

/**
 * Interface for simple Drawee controller builders.
 */
   simple Drawee controller builders的接口
public interface SimpleDraweeControllerBuilder {

  /** Sets the caller context. */
  设置调用者上下文
  SimpleDraweeControllerBuilder setCallerContext(Object callerContext);

  /** Sets the uri. */
  设置图像Uri
  SimpleDraweeControllerBuilder setUri(Uri uri);

  /** Sets the uri from a string. */
   设置图像Uri
  SimpleDraweeControllerBuilder setUri(@Nullable String uriString);

  /** Sets the old controller to be reused if possible. */
   
 如果有可能,设置旧的controller 用以重用
  SimpleDraweeControllerBuilder setOldController(@Nullable DraweeController oldController);

  /** Builds the specified controller. */
  构建具体的DraweeController  
  DraweeController build();
}

AbstractDraweeControllerBuilder 源码

/**
 * Base implementation for Drawee controller builders.
 */
public abstract class AbstractDraweeControllerBuilder <
    BUILDER extends AbstractDraweeControllerBuilder<BUILDER, REQUEST, IMAGE, INFO>,
    REQUEST,
    IMAGE,
    INFO>
    implements SimpleDraweeControllerBuilder {

  private static final ControllerListener<Object> sAutoPlayAnimationsListener =
      new BaseControllerListener<Object>() {
        @Override
        public void onFinalImageSet(String id, @Nullable Object info, @Nullable Animatable anim) {
          if (anim != null) {
            anim.start();
          }
        }
      };

  private static final NullPointerException NO_REQUEST_EXCEPTION =
      new NullPointerException("No image request was specified!");

  // components
  private final Context mContext;
  private final Set<ControllerListener> mBoundControllerListeners;

  // builder parameters
  private @Nullable Object mCallerContext;
  图片请求 ImageRequest
  private @Nullable REQUEST mImageRequest;
  底分辨率图片请求
  private @Nullable REQUEST mLowResImageRequest;
  多图片请求
  private @Nullable REQUEST[] mMultiImageRequests;
  private boolean mTryCacheOnlyFirst;
  数据源提供者
  private @Nullable Supplier<DataSource<IMAGE>> mDataSourceSupplier;
  private @Nullable ControllerListener<? super INFO> mControllerListener;
  private @Nullable ControllerViewportVisibilityListener mControllerViewportVisibilityListener;
  是否可点击重试
  private boolean mTapToRetryEnabled;
 是否需要自动播放动画
  private boolean mAutoPlayAnimations;
  private boolean mRetainImageOnFailure;
  private String mContentDescription;
  // old controller to reuse
  这个变量重要 重用的DraweeController ,其具体的对象,就给子类去构建
  private @Nullable DraweeController mOldController;

  private static final AtomicLong sIdCounter = new AtomicLong();

  protected AbstractDraweeControllerBuilder(
      Context context,
      Set<ControllerListener> boundControllerListeners) {
    mContext = context;
    mBoundControllerListeners = boundControllerListeners;
    init();
  }

  /** Initializes this builder. */
  private void init() {
    mCallerContext = null;
    mImageRequest = null;
    mLowResImageRequest = null;
    mMultiImageRequests = null;
    mTryCacheOnlyFirst = true;
    mControllerListener = null;
    mControllerViewportVisibilityListener = null;
    默认false
    mTapToRetryEnabled = false;
    默认不自动播放
    mAutoPlayAnimations = false;
    mOldController = null;
    mContentDescription = null;
  }
   ....其他方法
   /** Builds a regular controller. */
   构建一个常规的controller
  protected AbstractDraweeController buildController() {
    AbstractDraweeController controller = obtainController();
    controller.setRetainImageOnFailure(getRetainImageOnFailure());
    controller.setContentDescription(getContentDescription());
    controller.setControllerViewportVisibilityListener(getControllerViewportVisibilityListener());
    maybeBuildAndSetRetryManager(controller);
    maybeAttachListeners(controller);
    return controller;
  }
   /** Concrete builder classes should override this method to return a new controller. */
   这个抽象类的唯一抽象方法,又子类去实现构造具体的类
  protected abstract AbstractDraweeController obtainController();
   ...其他方法

AbstractDraweeControllerBuilder 的作用其实就是提供DraweeControllerBuilder所需要的所有成员变量,然后具体的变量值交给子类PipelineDraweeControllerBuilder去获取实现,并设置这些成员变量
PipelineDraweeControllerBuilder源码:


/**
 * Concrete implementation of ImagePipeline Drawee controller builder.
 * <p/> See {@link AbstractDraweeControllerBuilder} for more details.
 */
ImagePipeline Drawee controller builder.的具体实现

public class PipelineDraweeControllerBuilder extends AbstractDraweeControllerBuilder<
    PipelineDraweeControllerBuilder,
    ImageRequest,
    CloseableReference<CloseableImage>,
    ImageInfo> {
   
  重要的成员变量图像管道,final类型,初始化一遍不在变化,上篇文章中提到可以从ImagePipelineFactory中获取
  private final ImagePipeline mImagePipeline;

  重要的成员变量 PipelineDraweeControllerFactory是PipelineDraweeController工厂
  private final PipelineDraweeControllerFactory mPipelineDraweeControllerFactory;

  @Nullable
  private ImmutableList<DrawableFactory> mCustomDrawableFactories;

  public PipelineDraweeControllerBuilder(
      Context context,
      PipelineDraweeControllerFactory pipelineDraweeControllerFactory,
      ImagePipeline imagePipeline,
      Set<ControllerListener> boundControllerListeners) {
    super(context, boundControllerListeners);
    mImagePipeline = imagePipeline;
    mPipelineDraweeControllerFactory = pipelineDraweeControllerFactory;
  }

  @Override
  public PipelineDraweeControllerBuilder setUri(@Nullable Uri uri) {
    if (uri == null) {
      return super.setImageRequest(null);
    }
    设置图片Uri的的本质是: 用此Uri构建图像请求ImageRequest,实际上Fresco加载图片,都是构造ImageRequest
    ImageRequest imageRequest = ImageRequestBuilder.newBuilderWithSource(uri)
        .setRotationOptions(RotationOptions.autoRotateAtRenderTime())
        .build();
    return super.setImageRequest(imageRequest);
  }

  @Override
  public PipelineDraweeControllerBuilder setUri(@Nullable String uriString) {
    if (uriString == null || uriString.isEmpty()) {
      return super.setImageRequest(ImageRequest.fromUri(uriString));
    }
    return setUri(Uri.parse(uriString));
  }
  ...其他方法

  父级抽象类的抽象方法,重要方法  obtainController。
  @Override
  protected PipelineDraweeController obtainController() {
    先获取之前设置的OldController
    DraweeController oldController = getOldController();
    PipelineDraweeController controller;
    
    if (oldController instanceof PipelineDraweeController) {
     如果oldController 是PipelineDraweeController的实例 ,就在从controller的实例上修改一些需要的值,不用再实例化一个controller
      controller = (PipelineDraweeController) oldController;
      controller.initialize(
          obtainDataSourceSupplier(),
          generateUniqueControllerId(),
          getCacheKey(),
          getCallerContext(),
          mCustomDrawableFactories);
    } else {
      如果oldcontroller ==null 使用PipelineDraweeControllerFactory重新生成一个新的controller
      controller = mPipelineDraweeControllerFactory.newController(
          obtainDataSourceSupplier(),
          generateUniqueControllerId(),
          getCacheKey(),
          getCallerContext(),
          mCustomDrawableFactories);
    }
    return controller;
  }
 ...其他方法
}

这个类主要是为了设置一些builder所需要的值,并且构造除乐具体的controller。PipelineDraweeController的实例
PipelineDraweeController这个类是真正的DraweeController,这个下一章在分析。
PipelineDraweeControllerFactory是PipelineDraweeController的工厂类。用于常见controller实例。


/**
 * Default implementation of {@link PipelineDraweeControllerFactory}.
 */
public class PipelineDraweeControllerFactory {

  private Resources mResources;
  private DeferredReleaser mDeferredReleaser;
  private DrawableFactory mAnimatedDrawableFactory;
  private Executor mUiThreadExecutor;
  private MemoryCache<CacheKey, CloseableImage> mMemoryCache;
  @Nullable
  private ImmutableList<DrawableFactory> mDrawableFactories;
  @Nullable
  private Supplier<Boolean> mDebugOverlayEnabledSupplier;

  public void init(
      Resources resources,
      DeferredReleaser deferredReleaser,
      DrawableFactory animatedDrawableFactory,
      Executor uiThreadExecutor,
      MemoryCache<CacheKey, CloseableImage> memoryCache,
      @Nullable ImmutableList<DrawableFactory> drawableFactories,
      @Nullable Supplier<Boolean> debugOverlayEnabledSupplier) {
    mResources = resources;
    mDeferredReleaser = deferredReleaser;
    mAnimatedDrawableFactory = animatedDrawableFactory;
    mUiThreadExecutor = uiThreadExecutor;
    mMemoryCache = memoryCache;
    mDrawableFactories = drawableFactories;
    mDebugOverlayEnabledSupplier = debugOverlayEnabledSupplier;
  }

  public PipelineDraweeController newController(
      Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,
      String id,
      CacheKey cacheKey,
      Object callerContext) {
    return newController(dataSourceSupplier, id, cacheKey, callerContext, null);
  }

  public PipelineDraweeController newController(
      Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,
      String id,
      CacheKey cacheKey,
      Object callerContext,
      @Nullable ImmutableList<DrawableFactory> customDrawableFactories) {
    Preconditions.checkState(mResources != null, "init() not called");
    // Field values passed as arguments so that any subclass of PipelineDraweeControllerFactory
    // can simply override internalCreateController() and return a custom Drawee controller
    PipelineDraweeController controller = internalCreateController(
        mResources,
        mDeferredReleaser,
        mAnimatedDrawableFactory,
        mUiThreadExecutor,
        mMemoryCache,
        mDrawableFactories,
        customDrawableFactories,
        dataSourceSupplier,
        id,
        cacheKey,
        callerContext);
    if (mDebugOverlayEnabledSupplier != null) {
      controller.setDrawDebugOverlay(mDebugOverlayEnabledSupplier.get());
    }
    return controller;
  }
  内部创建PipelineDraweeController ,创建一个controller需要这么多参数,所以需要上面讲的重用controller的实例,只改变其中的几个成员变量值就行了。
  protected PipelineDraweeController internalCreateController(
      Resources resources,
      DeferredReleaser deferredReleaser,
      DrawableFactory animatedDrawableFactory,
      Executor uiThreadExecutor,
      MemoryCache<CacheKey, CloseableImage> memoryCache,
      @Nullable ImmutableList<DrawableFactory> globalDrawableFactories,
      @Nullable ImmutableList<DrawableFactory> customDrawableFactories,
      Supplier<DataSource<CloseableReference<CloseableImage>>> dataSourceSupplier,
      String id,
      CacheKey cacheKey,
      Object callerContext) {
    PipelineDraweeController controller = new PipelineDraweeController(
        resources,
        deferredReleaser,
        animatedDrawableFactory,
        uiThreadExecutor,
        memoryCache,
        dataSourceSupplier,
        id,
        cacheKey,
        callerContext,
        globalDrawableFactories);
    controller.setCustomDrawableFactories(customDrawableFactories);
    return controller;
  }
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,043评论 25 707
  • 作者:董存亮 2010.10.29 正文: 自传说“盘古开天地”和“女娲造人”以降,智慧的人们就不断思考:我们赖以...
    董存亮阅读 622评论 0 0
  • 今日励语: 当个人的才华还撑不起自己的野心时,就应该静下心来学习;当个人的能力还驾驭不了你自己的目标时,就应该沉下...
    七彩熏衣草阅读 379评论 0 0
  • 零度打卡Day27 主题阅读:《改变你一生的学习计划》 第四章节:高效学习方法笔记 每日橙思:偶也相信,虽然思维还...
    零度2013阅读 217评论 0 0