国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Fresco源碼分析之Controller

Kerr1Gan / 2088人閱讀

摘要:如果你是第一次看我的的源碼分析系列文章,這里強烈推薦你先閱讀我的前面兩篇文章源碼分析之與源碼分析之。其中是用來管理推遲資源釋放的。發送預處理請求,獲取相應類型的緩存數據。當數據源已經獲取到時,發送通知給訂閱者,因此分別回調訂閱者的方法。

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

Suppiler

PipelineDraweeControllerBuilderSupplier是一個供應商,主要實現了Supplier接口,它只有一個方法T get(),用來獲取相關的提供實現。因此該供應類提供的就是PipelineDraweeControllerBuilder實例。

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

在生成的builder中有4個參數,第一個是Context再熟悉不過了;第二個是Controller的工廠;第三個是數據管道ImagePipeline;第四個是listenerset集合,主要用在圖片請求之后的監聽回調。下面詳細說明后面三個參數內容與作用。

PipelineDraweeControllerFactory

在這個類中主要就兩個方法,分別為internalCreateControllernewController,對外的方法就一個newController。這個兩個方法都是用來創建PipelineDraweeController對象。其中newController內部就是調用了internalCreateController來進行創建PipelineDraweeController實例。

  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是用來管理推遲資源釋放的。我們在之前的文章已經提到,在onAttach中會進行加載資源,而onDetach中又會釋放資源。因為在Fresco中往往會在onDetachonAttach之間頻繁切換(view的顯隱、繪制與Controller的設置都會調用),并且它們都處于在同一個looper(其實就是主進程的looper)中。如果在onDetach時馬上釋放資源的話,這樣會造成資源的濫用,導致不必要的資源加載與釋放回收。所以就用了這個資源推遲釋放的機制(內部原理是使用了set集合的唯一性的特性)。

dataSourceSupplierDataSource的供應商,用來提供DataSource實例。而DataSource是用來獲取與存儲請求結果的,相當與圖片數據源。這些都會在后續的Controller中使用到。

ImagePipeline

既然它是數據管道,自然是與網絡請求與緩存數據有關。其實我們可以把它理解為多個管道的集合,最終顯示的圖片資源就是來自于它們中的其中一個。下面介紹其中的主要方法:

fetchDecodedImage() 發送請求,返回decode image的數據源。

fetchEncodedImage() 發送請求,返回encoded image的數據源。

prefetchToBitmapCache() 發送預處理請求,獲取預處理的bitmap緩存數據。

prefetchToDiskCache() 發送預處理請求,獲取預處理的磁盤緩存數據。

submitFetchRequest() 發送請求,獲取相應類型的數據源。

submitPrefetchRequest() 發送預處理請求,獲取相應類型的緩存數據。

這里用的最多的還是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,這是一個生產者,內部只有一個公共接口方法void produceResults(Consumer consumer, ProducerContext context),用來獲取數據源。其實我們會發現submitFetchRequest方法中的producer傳入的其實是一個隊列,因為內部會遞歸調用produceResults()來獲取最終的數據源。

關于Producer后續有時間的話會多帶帶開篇文章詳細分析。
ControllerListener

如果你對ControllerListener不熟悉的話,那么BaseControllerListener應該或多或少使用過吧。它其實就是ControllerListener的空實現。既然是監聽回調,那么來看下它提供的回調方法與調用時機。

void onSubmit(String id, Object callerContext) 在發送請求的時候回調

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

void onIntermediateImageSet(String id, @Nullable INFO imageInfo) 在發送請求與最終圖片設置的過程中回調

void onIntermediateImageFailed(String id, Throwable throwable) 在發送請求與最終失敗的過程中回調

void onFailure(String id, Throwable throwable) 發送請求失敗時回調

void onRelease(String id) 資源釋放時回調

ControllerBuilder

既然是builder模式,最終的目的自然就是用來創建Controller,所以我們可以直接奔著它的目的來分析。在這里Controllerbuilder類是PipelineDraweeControllerBuilder。我們找到它的build()發現在它的父類AbstractDraweeControllerBuilder中。但最終的創建實例方法還是調用了obtainController()抽象方法。所以經過反轉還是回到了PipelineDraweeControllerBuilder,那么我們直接來看下它創建方式。

  @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;
  }

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

  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();
      }
    };
  }

在這個方法中,我們一眼就看到了Supplier的創建,之前也提到它只有一個get()方法,就是用來提供所以需要的DataSource。在這里也是如此,這里它調用了getDataSourceForRequest()方法,該方法是一個抽象方法,細節實現由它的子類實現,所以我們可以再次回到getDataSourceForRequest,在其中就能夠搜索到getDataSourceForRequest()方法

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

看到上面的方法實現方法是否眼熟呢?這也是我們上面所提到的ImagePipleline中的方法,這里就不在多做分析了。這樣Controller就與獲取數據的通道建立了聯系。那么下面我們就轉戰到Controller中,看看它到底做了什么。

Controller

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

Drawable createDrawable(CloseableImage closeableImage) 這是內部類DrawableFactory中的方法,是一個工廠,不言而喻它是用來創建Drawable的,在數據源返回的時候回調,進而顯示到Hierarchy層。

getDataSource() 獲取數據源通道,與其建立聯系。

void setHierarchy(@Nullable DraweeHierarchy hierarchy) 設置Hierarchy圖層,內部持有的其實是SettableDraweeHierarchy接口對象。所以內部調用的也就是它的6個接口方法。之前的文章也有提及,用來控制圖片加載過程中的顯示邏輯。

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

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

在這個方法中mEventTracker是事件記錄器,默認是開啟的,如果要關閉則需要在Fresco.initialize()之前調用DraweeEventTracker.disable()關閉;然后就是將其從資源推遲釋放機制中取消;最后就是調用submitRequest()發送數據源請求。

  protected void submitRequest() {
    final T closeableImage = getCachedImage();
    //1.判斷內存緩存中是否存在
    if (closeableImage != null) {
      mDataSource = null;
      mIsRequestSubmitted = true;
      mHasFetchFailed = false;
       mEventTracker.recordEvent(Event.ON_SUBMIT_CACHE_HIT);
      //1.1數據獲取中通知回調
      getControllerListener().onSubmit(mId, mCallerContext);
      //1.2數據處理
      onNewResultInternal(mId, mDataSource, closeableImage, 1.0f, true, true);
      return;
    }
     mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT);
    //2.通過DataSource獲取數據源
    //2.1數據獲取中通知回調
    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();
    //內部請求數據回調,當數據源返回時回調
    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數據處理
            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();
            //數據進度處理
            onProgressUpdateInternal(id, dataSource, progress, isFinished);
          }
        };
    //數據源訂閱回調注冊
    mDataSource.subscribe(dataSubscriber, mUiThreadImmediateExecutor);
  }

邏輯方面的處理,上面代碼中已經詳細注釋了,總的來說就是先從內存中獲取如果存在就直接拿來用,否則就通過DataSource從網絡或者是本地資源中獲取。使用DataSource方式會使用到DataSubscriber,即訂閱方式。當數據源已經獲取到時,發送通知給訂閱者,因此分別回調訂閱者的方法。上述兩種方式只要成功了都會交由onNewResultInternal()處理,而失敗則由onFailureInternal()處理,同時請求進度處理由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;
        //通過hierarchy(GenericDraweeHierarchy)來設置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);
      }
    }
  }

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

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

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

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);
  }

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

End

本篇文章主要分析了Fresco中的Controller相關處理邏輯,它控制著Hierarchy顯示邏輯,同時它是數據源的獲取橋梁通過DataSource來鏈接數據源的獲取。那么問題又來了,DataSource又是如何產生的呢?同時它的內部邏輯又是如何的呢?這就涉及到Producer了,敬請關注下篇文章Fresco源碼分析之Producer

Fresco源碼分析系列Github地址

關注

Recommend

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

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/68076.html

相關文章

  • Fresco源碼分析DraweeView

    摘要:首先這是對的源碼分析,所以在看這篇文章之前你應該要有使用的基礎,如果沒有的強烈推薦看下官方文檔。在中統一由來替代。關于后續文章會詳細分析。在其內部的,是用來記錄事件的傳遞,方便的調試。這次主要是分析了中的基本組件與它的子類。 在Android中圖片加載的框架很多,例如:Fresco、Picasso、Glide與Imageloader。它們都有各自的優點,但總的來說,使用起來方便簡單、可...

    draveness 評論0 收藏0
  • Fresco源碼分析Hierarchy

    摘要:最終的顯隱操作都會轉化為在方法中進行操作。主要是通過與數組來控制數組中各個的值,即顯隱它繼承于,顧名思義通過矩陣來改變狀態。 上篇文章我們分析了Fresco中的DraweeView,對其中的一些原理以及方法進行了解析。在這過程中我們了解到,DraweeView中是通過DraweeHolder來統一管理的。而DraweeHolder又是用來統一管理相關的Hierarchy與Control...

    jzzlee 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<