Fresco圖片框架實現(xiàn)原理(二):DraweeController

接上文《Fresco圖片框架實現(xiàn)原理(一)》文末

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

在研究正真的PipelineDraweeController之前,先來看看PipelineDraweeControllerBuilder在Fresco中的構造原理和過程

從上面的函數(shù)我們一個一個往里面點

image.png

PipelineDraweeControllerBuilderSupplier是一個提供者模式邮利,主要是為了構造PipelineDraweeControllerBuilder類
圖像管道Drawee contrller builder的具體實現(xiàn)類
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;
  數(shù)據源提供者
  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. */
   構建一個常規(guī)的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. */
   這個抽象類的唯一抽象方法辟拷,又子類去實現(xiàn)構造具體的類
  protected abstract AbstractDraweeController obtainController();
   ...其他方法

AbstractDraweeControllerBuilder 的作用其實就是提供DraweeControllerBuilder所需要的所有成員變量智政,然后具體的變量值交給子類PipelineDraweeControllerBuilder去獲取實現(xiàn)质涛,并設置這些成員變量
PipelineDraweeControllerBuilder源碼:


/**
 * Concrete implementation of ImagePipeline Drawee controller builder.
 * <p/> See {@link AbstractDraweeControllerBuilder} for more details.
 */
ImagePipeline Drawee controller builder.的具體實現(xiàn)

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;
  }
  內部創(chuàng)建PipelineDraweeController 问潭,創(chuàng)建一個controller需要這么多參數(shù)猿诸,所以需要上面講的重用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;
  }
}
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末梳虽,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子灾茁,更是在濱河造成了極大的恐慌窜觉,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件北专,死亡現(xiàn)場離奇詭異禀挫,居然都是意外死亡,警方通過查閱死者的電腦和手機拓颓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門语婴,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人驶睦,你說我怎么就攤上這事砰左。” “怎么了场航?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵菜职,是天一觀的道長。 經常有香客問我旗闽,道長酬核,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任适室,我火速辦了婚禮嫡意,結果婚禮上,老公的妹妹穿的比我還像新娘捣辆。我一直安慰自己蔬螟,他們只是感情好,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布汽畴。 她就那樣靜靜地躺著旧巾,像睡著了一般耸序。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上鲁猩,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天坎怪,我揣著相機與錄音,去河邊找鬼廓握。 笑死搅窿,一個胖子當著我的面吹牛,可吹牛的內容都是我干的隙券。 我是一名探鬼主播男应,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼娱仔!你這毒婦竟也來了沐飘?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤牲迫,失蹤者是張志新(化名)和其女友劉穎耐朴,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恩溅,經...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年谓娃,在試婚紗的時候發(fā)現(xiàn)自己被綠了脚乡。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡滨达,死狀恐怖奶稠,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情捡遍,我是刑警寧澤锌订,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站画株,受9級特大地震影響辆飘,放射性物質發(fā)生泄漏。R本人自食惡果不足惜谓传,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一蜈项、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧续挟,春花似錦紧卒、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽轴总。三九已至,卻和暖如春博个,著一層夾襖步出監(jiān)牢的瞬間怀樟,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工坡倔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留漂佩,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓罪塔,卻偏偏與公主長得像投蝉,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子征堪,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,099評論 25 707
  • 作者:董存亮 2010.10.29 正文: 自傳說“盤古開天地”和“女媧造人”以降瘩缆,智慧的人們就不斷思考:我們賴以...
    董存亮閱讀 640評論 0 0
  • 今日勵語: 當個人的才華還撐不起自己的野心時,就應該靜下心來學習佃蚜;當個人的能力還駕馭不了你自己的目標時庸娱,就應該沉下...
    七彩熏衣草閱讀 384評論 0 0
  • 零度打卡Day27 主題閱讀:《改變你一生的學習計劃》 第四章節(jié):高效學習方法筆記 每日橙思:偶也相信,雖然思維還...
    零度2013閱讀 225評論 0 0