成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Fresco源碼分析之Controller

Kerr1Gan / 2096人閱讀

摘要:如果你是第一次看我的的源碼分析系列文章,這里強(qiáng)烈推薦你先閱讀我的前面兩篇文章源碼分析之與源碼分析之。其中是用來(lái)管理推遲資源釋放的。發(fā)送預(yù)處理請(qǐng)求,獲取相應(yīng)類型的緩存數(shù)據(jù)。當(dāng)數(shù)據(jù)源已經(jīng)獲取到時(shí),發(fā)送通知給訂閱者,因此分別回調(diào)訂閱者的方法。

如果你是第一次看我的Fresco的源碼分析系列文章,這里強(qiáng)烈推薦你先閱讀我的前面兩篇文章Fresco源碼分析之DraweeView與Fresco源碼分析之Hierarchy。好了,下面進(jìn)入正題。在上篇文章中我們提到,在Fresco中關(guān)于圖片的緩存、請(qǐng)求與顯示邏輯處理都在Controller中。那么Controller到底是如何貫穿這些功能的呢?我們先從它的出生開始。

Suppiler

PipelineDraweeControllerBuilderSupplier是一個(gè)供應(yīng)商,主要實(shí)現(xiàn)了Supplier接口,它只有一個(gè)方法T get(),用來(lái)獲取相關(guān)的提供實(shí)現(xiàn)。因此該供應(yīng)類提供的就是PipelineDraweeControllerBuilder實(shí)例。

  @Override
  public PipelineDraweeControllerBuilder get() {
    return new PipelineDraweeControllerBuilder(
        mContext,
        mPipelineDraweeControllerFactory,
        mImagePipeline,
        mBoundControllerListeners);
  }

在生成的builder中有4個(gè)參數(shù),第一個(gè)是Context再熟悉不過(guò)了;第二個(gè)是Controller的工廠;第三個(gè)是數(shù)據(jù)管道ImagePipeline;第四個(gè)是listenerset集合,主要用在圖片請(qǐng)求之后的監(jiān)聽回調(diào)。下面詳細(xì)說(shuō)明后面三個(gè)參數(shù)內(nèi)容與作用。

PipelineDraweeControllerFactory

在這個(gè)類中主要就兩個(gè)方法,分別為internalCreateControllernewController,對(duì)外的方法就一個(gè)newController。這個(gè)兩個(gè)方法都是用來(lái)創(chuàng)建PipelineDraweeController對(duì)象。其中newController內(nèi)部就是調(diào)用了internalCreateController來(lái)進(jìn)行創(chuàng)建PipelineDraweeController實(shí)例。

  protected PipelineDraweeController internalCreateController(
      Resources resources,
      DeferredReleaser deferredReleaser,
      DrawableFactory animatedDrawableFactory,
      Executor uiThreadExecutor,
      MemoryCache memoryCache,
      @Nullable ImmutableList globalDrawableFactories,
      @Nullable ImmutableList customDrawableFactories,
       Supplier>> 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;
  }

其中DeferredReleaser是用來(lái)管理推遲資源釋放的。我們?cè)谥暗奈恼乱呀?jīng)提到,在onAttach中會(huì)進(jìn)行加載資源,而onDetach中又會(huì)釋放資源。因?yàn)樵?strong>Fresco中往往會(huì)在onDetachonAttach之間頻繁切換(view的顯隱、繪制與Controller的設(shè)置都會(huì)調(diào)用),并且它們都處于在同一個(gè)looper(其實(shí)就是主進(jìn)程的looper)中。如果在onDetach時(shí)馬上釋放資源的話,這樣會(huì)造成資源的濫用,導(dǎo)致不必要的資源加載與釋放回收。所以就用了這個(gè)資源推遲釋放的機(jī)制(內(nèi)部原理是使用了set集合的唯一性的特性)。

dataSourceSupplierDataSource的供應(yīng)商,用來(lái)提供DataSource實(shí)例。而DataSource是用來(lái)獲取與存儲(chǔ)請(qǐng)求結(jié)果的,相當(dāng)與圖片數(shù)據(jù)源。這些都會(huì)在后續(xù)的Controller中使用到。

ImagePipeline

既然它是數(shù)據(jù)管道,自然是與網(wǎng)絡(luò)請(qǐng)求與緩存數(shù)據(jù)有關(guān)。其實(shí)我們可以把它理解為多個(gè)管道的集合,最終顯示的圖片資源就是來(lái)自于它們中的其中一個(gè)。下面介紹其中的主要方法:

fetchDecodedImage() 發(fā)送請(qǐng)求,返回decode image的數(shù)據(jù)源。

fetchEncodedImage() 發(fā)送請(qǐng)求,返回encoded image的數(shù)據(jù)源。

prefetchToBitmapCache() 發(fā)送預(yù)處理請(qǐng)求,獲取預(yù)處理的bitmap緩存數(shù)據(jù)。

prefetchToDiskCache() 發(fā)送預(yù)處理請(qǐng)求,獲取預(yù)處理的磁盤緩存數(shù)據(jù)。

submitFetchRequest() 發(fā)送請(qǐng)求,獲取相應(yīng)類型的數(shù)據(jù)源。

submitPrefetchRequest() 發(fā)送預(yù)處理請(qǐng)求,獲取相應(yīng)類型的緩存數(shù)據(jù)。

這里用的最多的還是fetchDecodedImage()

  public DataSource> fetchDecodedImage(
      ImageRequest imageRequest,
      Object callerContext,
      ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit) {
    try {
      Producer> producerSequence =
           mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
      return submitFetchRequest(
          producerSequence,
          imageRequest,
          lowestPermittedRequestLevelOnSubmit,
          callerContext);
    } catch (Exception exception) {
      return DataSources.immediateFailedDataSource(exception);
    }
  }

這里主要涉及到Producer,這是一個(gè)生產(chǎn)者,內(nèi)部只有一個(gè)公共接口方法void produceResults(Consumer consumer, ProducerContext context),用來(lái)獲取數(shù)據(jù)源。其實(shí)我們會(huì)發(fā)現(xiàn)submitFetchRequest方法中的producer傳入的其實(shí)是一個(gè)隊(duì)列,因?yàn)閮?nèi)部會(huì)遞歸調(diào)用produceResults()來(lái)獲取最終的數(shù)據(jù)源。

關(guān)于Producer后續(xù)有時(shí)間的話會(huì)多帶帶開篇文章詳細(xì)分析。
ControllerListener

如果你對(duì)ControllerListener不熟悉的話,那么BaseControllerListener應(yīng)該或多或少使用過(guò)吧。它其實(shí)就是ControllerListener的空實(shí)現(xiàn)。既然是監(jiān)聽回調(diào),那么來(lái)看下它提供的回調(diào)方法與調(diào)用時(shí)機(jī)。

void onSubmit(String id, Object callerContext) 在發(fā)送請(qǐng)求的時(shí)候回調(diào)

void onFinalImageSet(String id, @Nullable INFO imageInfo, @Nullable Animatable animatable) 在最終設(shè)置image圖片時(shí)回調(diào),其中imageInfo包含圖片的相關(guān)基本信息(width、height與quality)

void onIntermediateImageSet(String id, @Nullable INFO imageInfo) 在發(fā)送請(qǐng)求與最終圖片設(shè)置的過(guò)程中回調(diào)

void onIntermediateImageFailed(String id, Throwable throwable) 在發(fā)送請(qǐng)求與最終失敗的過(guò)程中回調(diào)

void onFailure(String id, Throwable throwable) 發(fā)送請(qǐng)求失敗時(shí)回調(diào)

void onRelease(String id) 資源釋放時(shí)回調(diào)

ControllerBuilder

既然是builder模式,最終的目的自然就是用來(lái)創(chuàng)建Controller,所以我們可以直接奔著它的目的來(lái)分析。在這里Controllerbuilder類是PipelineDraweeControllerBuilder。我們找到它的build()發(fā)現(xiàn)在它的父類AbstractDraweeControllerBuilder中。但最終的創(chuàng)建實(shí)例方法還是調(diào)用了obtainController()抽象方法。所以經(jīng)過(guò)反轉(zhuǎn)還是回到了PipelineDraweeControllerBuilder,那么我們直接來(lái)看下它創(chuàng)建方式。

  @Override
  protected PipelineDraweeController obtainController() {
    DraweeController oldController = getOldController();
    PipelineDraweeController controller;
    if (oldController instanceof PipelineDraweeController) {
      controller = (PipelineDraweeController) oldController;
      controller.initialize(
          obtainDataSourceSupplier(),
          generateUniqueControllerId(),
          getCacheKey(),
          getCallerContext(),
          mCustomDrawableFactories);
    } else {
      controller = mPipelineDraweeControllerFactory.newController(
          obtainDataSourceSupplier(),
          generateUniqueControllerId(),
          getCacheKey(),
          getCallerContext(),
          mCustomDrawableFactories);
    }
    return controller;
  }

通過(guò)上面的代碼,邏輯已經(jīng)很明顯了。首先判斷是否已經(jīng)存在Controller,如果存在的話就無(wú)需創(chuàng)建新的實(shí)例,只需調(diào)用initialize()方法進(jìn)行重寫初始化;如果不存在,那么就調(diào)用我們文章之前分析的PipelineDraweeControllerFactory中的newController()來(lái)創(chuàng)建新的實(shí)例。這里主要的參數(shù)還是obtainDataSourceSupplier(),之前也簡(jiǎn)單提到了,它是DataSource的供應(yīng)者。那么我們來(lái)看下Supplier的創(chuàng)建

  protected Supplier> getDataSourceSupplierForRequest(
      final REQUEST imageRequest,
      final CacheLevel cacheLevel) {
    final Object callerContext = getCallerContext();
    return new Supplier>() {
      @Override
      public DataSource get() {
        return getDataSourceForRequest(imageRequest, callerContext, cacheLevel);
      }
      @Override
      public String toString() {
        return Objects.toStringHelper(this)
            .add("request", imageRequest.toString())
            .toString();
      }
    };
  }

在這個(gè)方法中,我們一眼就看到了Supplier的創(chuàng)建,之前也提到它只有一個(gè)get()方法,就是用來(lái)提供所以需要的DataSource。在這里也是如此,這里它調(diào)用了getDataSourceForRequest()方法,該方法是一個(gè)抽象方法,細(xì)節(jié)實(shí)現(xiàn)由它的子類實(shí)現(xiàn),所以我們可以再次回到getDataSourceForRequest,在其中就能夠搜索到getDataSourceForRequest()方法

  @Override
  protected DataSource> getDataSourceForRequest(
      ImageRequest imageRequest,
      Object callerContext,
      CacheLevel cacheLevel) {
    return mImagePipeline.fetchDecodedImage(
        imageRequest,
        callerContext,
        convertCacheLevelToRequestLevel(cacheLevel));
  }

看到上面的方法實(shí)現(xiàn)方法是否眼熟呢?這也是我們上面所提到的ImagePipleline中的方法,這里就不在多做分析了。這樣Controller就與獲取數(shù)據(jù)的通道建立了聯(lián)系。那么下面我們就轉(zhuǎn)戰(zhàn)到Controller中,看看它到底做了什么。

Controller

PipelineDraweeController繼承于AbstractDraweeController,在PipelineDraweeController中主要的方法有三個(gè)

Drawable createDrawable(CloseableImage closeableImage) 這是內(nèi)部類DrawableFactory中的方法,是一個(gè)工廠,不言而喻它是用來(lái)創(chuàng)建Drawable的,在數(shù)據(jù)源返回的時(shí)候回調(diào),進(jìn)而顯示到Hierarchy層。

getDataSource() 獲取數(shù)據(jù)源通道,與其建立聯(lián)系。

void setHierarchy(@Nullable DraweeHierarchy hierarchy) 設(shè)置Hierarchy圖層,內(nèi)部持有的其實(shí)是SettableDraweeHierarchy接口對(duì)象。所以內(nèi)部調(diào)用的也就是它的6個(gè)接口方法。之前的文章也有提及,用來(lái)控制圖片加載過(guò)程中的顯示邏輯。

其余的邏輯處理都在它的父類AbstractDraweeController中。在之前我們多次提及到onAttachonDetach方法,它們分別是處理數(shù)據(jù)加載與釋放。

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);
    //取消資源推遲釋放機(jī)制,防止資源被釋放
    mDeferredReleaser.cancelDeferredRelease(this);
    mIsAttached = true;
    if (!mIsRequestSubmitted) {
      submitRequest();
    }
  }

在這個(gè)方法中mEventTracker是事件記錄器,默認(rèn)是開啟的,如果要關(guān)閉則需要在Fresco.initialize()之前調(diào)用DraweeEventTracker.disable()關(guān)閉;然后就是將其從資源推遲釋放機(jī)制中取消;最后就是調(diào)用submitRequest()發(fā)送數(shù)據(jù)源請(qǐng)求。

  protected void submitRequest() {
    final T closeableImage = getCachedImage();
    //1.判斷內(nèi)存緩存中是否存在
    if (closeableImage != null) {
      mDataSource = null;
      mIsRequestSubmitted = true;
      mHasFetchFailed = false;
       mEventTracker.recordEvent(Event.ON_SUBMIT_CACHE_HIT);
      //1.1數(shù)據(jù)獲取中通知回調(diào)
      getControllerListener().onSubmit(mId, mCallerContext);
      //1.2數(shù)據(jù)處理
      onNewResultInternal(mId, mDataSource, closeableImage, 1.0f, true, true);
      return;
    }
     mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT);
    //2.通過(guò)DataSource獲取數(shù)據(jù)源
    //2.1數(shù)據(jù)獲取中通知回調(diào)
    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();
    //內(nèi)部請(qǐng)求數(shù)據(jù)回調(diào),當(dāng)數(shù)據(jù)源返回時(shí)回調(diào)
    final DataSubscriber dataSubscriber =
        new BaseDataSubscriber() {
          @Override
          public void onNewResultImpl(DataSource 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();
            //2.2數(shù)據(jù)處理
            if (image != null) {
              //成功處理
              onNewResultInternal(id, dataSource, image, progress, isFinished, wasImmediate);
            } else if (isFinished) {
              //失敗處理
              onFailureInternal(id, dataSource, new NullPointerException(), /* isFinished */ true);
            }
          }
          @Override
          public void onFailureImpl(DataSource dataSource) {
            //失敗處理
            onFailureInternal(id, dataSource, dataSource.getFailureCause(), /* isFinished */ true);
          }
          @Override
          public void onProgressUpdate(DataSource dataSource) {
            boolean isFinished = dataSource.isFinished();
            float progress = dataSource.getProgress();
            //數(shù)據(jù)進(jìn)度處理
            onProgressUpdateInternal(id, dataSource, progress, isFinished);
          }
        };
    //數(shù)據(jù)源訂閱回調(diào)注冊(cè)
    mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor);
  }

邏輯方面的處理,上面代碼中已經(jīng)詳細(xì)注釋了,總的來(lái)說(shuō)就是先從內(nèi)存中獲取如果存在就直接拿來(lái)用,否則就通過(guò)DataSource從網(wǎng)絡(luò)或者是本地資源中獲取。使用DataSource方式會(huì)使用到DataSubscriber,即訂閱方式。當(dāng)數(shù)據(jù)源已經(jīng)獲取到時(shí),發(fā)送通知給訂閱者,因此分別回調(diào)訂閱者的方法。上述兩種方式只要成功了都會(huì)交由onNewResultInternal()處理,而失敗則由onFailureInternal()處理,同時(shí)請(qǐng)求進(jìn)度處理由onProgressUpdateInternal()處理。

  private void onNewResultInternal(
      String id,
      DataSource dataSource,
      @Nullable T image,
      float progress,
      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;
        //通過(guò)hierarchy(GenericDraweeHierarchy)來(lái)設(shè)置image
        mSettableDraweeHierarchy.setImage(drawable, 1f, wasImmediate);
        getControllerListener().onFinalImageSet(id, getImageInfo(image), getAnimatable());
        // IMPORTANT: do not execute any instance-specific code after this point
      } else {
        logMessageAndImage("set_intermediate_result @ onNewResult", image);
        mSettableDraweeHierarchy.setImage(drawable, progress, wasImmediate);
         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);
      }
    }
  }

這里我們主要就看里面的兩個(gè)try。
第一個(gè)使用createDrawable(image)將拿到的數(shù)據(jù)源轉(zhuǎn)變成Drawable,這個(gè)方法的具體實(shí)現(xiàn)是在子類中實(shí)現(xiàn)(上面也有提及)。
第二個(gè)分為兩種情況,一方面如果數(shù)據(jù)源已經(jīng)全部獲取完,則直接調(diào)用SettableDraweeHierarchy接口的setImage()方法將圖片設(shè)置到Hierarchy圖層上,同時(shí)調(diào)用Listener的回調(diào)方法onFinalImageSet();另一方面如果數(shù)據(jù)源還在獲取中,也是調(diào)用SettableDraweeHierarchy接口的setImage()方法,只是其中的參數(shù)progress根據(jù)進(jìn)度來(lái)設(shè)置而已,由于還處于資源獲取中所以調(diào)用onIntermediateImageSet()回調(diào)。
這樣Controller就與Hierarchy聯(lián)系起來(lái)了,將需要的圖片設(shè)置到顯示的圖片中。

對(duì)于SettableDraweeHierarchy中的這些方法如果不理解的可以回過(guò)頭去看我之前的這篇文章Fresco源碼分析之Hierarchy

由于源碼太多,對(duì)于onFailureInternal()onProgressUpdateInternal()這里就不貼出源碼來(lái)進(jìn)行分析了。原理與調(diào)用的方法基本類似,如果想看源碼的可以點(diǎn)這里

onDetach
  @Override
  public void onDetach() {
    if (FLog.isLoggable(FLog.VERBOSE)) {
      FLog.v(TAG, "controller %x %s: onDetach", System.identityHashCode(this), mId);
    }
    mEventTracker.recordEvent(Event.ON_DETACH_CONTROLLER);
    mIsAttached = false;
    mDeferredReleaser.scheduleDeferredRelease(this);
  }

相對(duì)于之前的分析onDetach()就簡(jiǎn)單多了,這里它只是對(duì)資源進(jìn)行釋放,釋放的策略也是推遲釋放策略DeferredReleaser。

End

本篇文章主要分析了Fresco中的Controller相關(guān)處理邏輯,它控制著Hierarchy顯示邏輯,同時(shí)它是數(shù)據(jù)源的獲取橋梁通過(guò)DataSource來(lái)鏈接數(shù)據(jù)源的獲取。那么問(wèn)題又來(lái)了,DataSource又是如何產(chǎn)生的呢?同時(shí)它的內(nèi)部邏輯又是如何的呢?這就涉及到Producer了,敬請(qǐng)關(guān)注下篇文章Fresco源碼分析之Producer

Fresco源碼分析系列Github地址

關(guān)注

Recommend

Fresco源碼分析之DraweeView
Fresco源碼分析之Hierarchy
Android共享動(dòng)畫兼容實(shí)現(xiàn)
Kotlin最佳實(shí)踐
RecyclerView下拉刷新與上拉更多
Android高仿微信之mvp實(shí)現(xiàn)(四)
tensorflow-梯度下降,有這一篇就足夠了
博客

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68076.html

相關(guān)文章

  • Fresco源碼分析DraweeView

    摘要:首先這是對(duì)的源碼分析,所以在看這篇文章之前你應(yīng)該要有使用的基礎(chǔ),如果沒(méi)有的強(qiáng)烈推薦看下官方文檔。在中統(tǒng)一由來(lái)替代。關(guān)于后續(xù)文章會(huì)詳細(xì)分析。在其內(nèi)部的,是用來(lái)記錄事件的傳遞,方便的調(diào)試。這次主要是分析了中的基本組件與它的子類。 在Android中圖片加載的框架很多,例如:Fresco、Picasso、Glide與Imageloader。它們都有各自的優(yōu)點(diǎn),但總的來(lái)說(shuō),使用起來(lái)方便簡(jiǎn)單、可...

    draveness 評(píng)論0 收藏0
  • Fresco源碼分析Hierarchy

    摘要:最終的顯隱操作都會(huì)轉(zhuǎn)化為在方法中進(jìn)行操作。主要是通過(guò)與數(shù)組來(lái)控制數(shù)組中各個(gè)的值,即顯隱它繼承于,顧名思義通過(guò)矩陣來(lái)改變狀態(tài)。 上篇文章我們分析了Fresco中的DraweeView,對(duì)其中的一些原理以及方法進(jìn)行了解析。在這過(guò)程中我們了解到,DraweeView中是通過(guò)DraweeHolder來(lái)統(tǒng)一管理的。而DraweeHolder又是用來(lái)統(tǒng)一管理相關(guān)的Hierarchy與Control...

    jzzlee 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<