Fresco圖片加載源碼淺析

前言

Fresco 中設(shè)計有一個叫做 image pipeline 的模塊余爆。它負(fù)責(zé)從網(wǎng)絡(luò)斋配,從本地文件系統(tǒng),本地資源加載圖片寄悯。為了最大限度節(jié)省空間和CPU時間萤衰,它含有3級緩存設(shè)計(2級內(nèi)存,1級文件)猜旬。

Fresco 中設(shè)計有一個叫做 Drawees 模塊脆栋,方便地顯示loading圖,當(dāng)圖片不再顯示在屏幕上時洒擦,及時地釋放內(nèi)存和空間占用椿争。

使用

Fresco使用:

首先需要在layout布局上使用fresco的simpleDraweeView:

<com.facebook.drawee.view.SimpleDraweeView
    android:id="@+id/simpleDraweeView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

然后再java代碼中使用:

    SimpleDraweeView simpleDraweeView = findViewById(R.id.simpleDraweeView);
    Uri uri = Uri.parse("https://www.baidu.com/img/xinshouye_034fec51df225fe8410f36ad3f2fccf6.png");
    simpleDraweeView.setImageURI(uri);

由上述使用方法可以看出,只需要給定一個容器然后傳入一個url地址熟嫩,即可完成對圖片的加載丘薛;那么它的內(nèi)部運行流程是什么樣的呢?

fresco整個業(yè)務(wù)流程:

E:\我的圖片\20160523111021635.png

入口

很明顯邦危,SimpleDraweeView是我們先要弄清楚的,首先要明白它是繼承自ImageView的,并且具有l(wèi)ayout布局洋侨,顯然是自定義View,第一步必然是從布局文件樣式中讀取屬性值。

那么我們直接看看simpleDraweeView.setImageURI(uri)方法:

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

首先它創(chuàng)建了一個Controller并調(diào)用setController倦蚪,看一下Controller是怎么創(chuàng)建的:

@Override
  public AbstractDraweeController build() {
    validate();
    //賦值圖片請求
    // if only a low-res request is specified, treat it as a final request.
    if (mImageRequest == null && mMultiImageRequests == null && mLowResImageRequest != null) {
      mImageRequest = mLowResImageRequest;
      mLowResImageRequest = null;
    }
    //創(chuàng)建ontroller
    return buildController();
  }

protected AbstractDraweeController buildController() {
    AbstractDraweeController controller = obtainController();//獲取請求
    controller.setRetainImageOnFailure(getRetainImageOnFailure());
    controller.setContentDescription(getContentDescription());
    controller.setControllerViewportVisibilityListener(getControllerViewportVisibilityListener());
    maybeBuildAndSetRetryManager(controller);
    maybeAttachListeners(controller);
    return controller;
  }


@Override
  protected PipelineDraweeController obtainController() {
    DraweeController oldController = getOldController();
    PipelineDraweeController controller;
    if (oldController instanceof PipelineDraweeController) {
      controller = (PipelineDraweeController) oldController;
      controller.initialize(
          obtainDataSourceSupplier(),
          generateUniqueControllerId(),
          getCacheKey(),
          getCallerContext(),
          mCustomDrawableFactories);
    } else {
        //工廠模式創(chuàng)建Controller
      controller = mPipelineDraweeControllerFactory.newController(
          obtainDataSourceSupplier(),
          generateUniqueControllerId(),
          getCacheKey(),
          getCallerContext(),
          mCustomDrawableFactories);
    }
    return controller;
  }


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
    //創(chuàng)建Controller
    PipelineDraweeController controller = internalCreateController(
        mResources,
        mDeferredReleaser,
        mAnimatedDrawableFactory,
        mUiThreadExecutor,
        mMemoryCache,
        mDrawableFactories,
        customDrawableFactories,
        dataSourceSupplier,
        id,
        cacheKey,
        callerContext);
    if (mDebugOverlayEnabledSupplier != null) {
      controller.setDrawDebugOverlay(mDebugOverlayEnabledSupplier.get());
    }
    return 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) {
    //至此Controller創(chuàng)建完畢 為PipelineDraweeController實例
    PipelineDraweeController controller = new PipelineDraweeController(
        resources,
        deferredReleaser,
        animatedDrawableFactory,
        uiThreadExecutor,
        memoryCache,
        dataSourceSupplier,
        id,
        cacheKey,
        callerContext,
        globalDrawableFactories);
    controller.setCustomDrawableFactories(customDrawableFactories);
    return controller;
  }

接下來希坚,讓我們看一看setController方法:

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

繼續(xù)追蹤mDraweeHolder.setController(draweeController):

public void setController(@Nullable DraweeController draweeController) {
    boolean wasAttached = mIsControllerAttached;
    if (wasAttached) {
      detachController();
    }

    // Clear the old controller
    if (isControllerValid()) {
      mEventTracker.recordEvent(Event.ON_CLEAR_OLD_CONTROLLER);
      mController.setHierarchy(null);
    }
    mController = draweeController;
    if (mController != null) {
      mEventTracker.recordEvent(Event.ON_SET_CONTROLLER);
      mController.setHierarchy(mHierarchy);
    } else {
      mEventTracker.recordEvent(Event.ON_CLEAR_CONTROLLER);
    }

    if (wasAttached) {
      attachController();
    }
  }

將draweeController賦值給mController,然后調(diào)用attachController方法:

private void attachController() {
    if (mIsControllerAttached) {
      return;
    }
    mEventTracker.recordEvent(Event.ON_ATTACH_CONTROLLER);
    mIsControllerAttached = true;
    if (mController != null &&
        mController.getHierarchy() != null) {
      mController.onAttach();
    }
  }

繼續(xù)追蹤onAttach方法:

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();//提交數(shù)據(jù)請求
    }
  }

終于看到提交數(shù)據(jù)請求了:

protected void submitRequest() {
    //獲取內(nèi)存緩存
    final T closeableImage = getCachedImage();
    if (closeableImage != null) {
      mDataSource = null;
      mIsRequestSubmitted = true;
      mHasFetchFailed = false;
      mEventTracker.recordEvent(Event.ON_SUBMIT_CACHE_HIT);
      getControllerListener().onSubmit(mId, mCallerContext);
      onNewResultInternal(mId, mDataSource, closeableImage, 1.0f, true, true);
      return;
    }
    mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT);
    getControllerListener().onSubmit(mId, mCallerContext);
    mSettableDraweeHierarchy.setProgress(0, true);
    mIsRequestSubmitted = true;
    mHasFetchFailed = false;
    //獲取數(shù)據(jù)~~~    
    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();
    //觀察者訂閱數(shù)據(jù)請求
    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();
            float progress = dataSource.getProgress();
            T image = dataSource.getResult();
            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<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);
  }

可以看到數(shù)據(jù)請求邏輯在getDataSource里面:

@Override
  protected DataSource<CloseableReference<CloseableImage>> getDataSource() {
    if (FLog.isLoggable(FLog.VERBOSE)) {
      FLog.v(TAG, "controller %x: getDataSource", System.identityHashCode(this));
    }
    return mDataSourceSupplier.get();
  }

最終getDataSource將數(shù)據(jù)請求交給了mDataSourceSupplier.get(),那么mDataSourceSupplier是何方神圣呢陵且?mDataSourceSupplier是什么時候初始化的呢裁僧?

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

我們發(fā)現(xiàn),在創(chuàng)建controller的時候會傳遞obtainDataSourceSupplier方法為參數(shù):

protected Supplier<DataSource<IMAGE>> obtainDataSourceSupplier() {
    if (mDataSourceSupplier != null) {
      return mDataSourceSupplier;
    }

    Supplier<DataSource<IMAGE>> supplier = null;

    // final image supplier;
    if (mImageRequest != null) {
        //獲取網(wǎng)絡(luò)數(shù)據(jù)提供者
      supplier = getDataSourceSupplierForRequest(mImageRequest);
    } else if (mMultiImageRequests != null) {
      supplier = getFirstAvailableDataSourceSupplier(mMultiImageRequests, mTryCacheOnlyFirst);
    }

    // increasing-quality supplier; highest-quality supplier goes first
    if (supplier != null && mLowResImageRequest != null) {
      List<Supplier<DataSource<IMAGE>>> suppliers = new ArrayList<>(2);
      suppliers.add(supplier);
      suppliers.add(getDataSourceSupplierForRequest(mLowResImageRequest));
      supplier = IncreasingQualityDataSourceSupplier.create(suppliers);
    }

    // no image requests; use null data source supplier
    if (supplier == null) {
      supplier = DataSources.getFailedDataSourceSupplier(NO_REQUEST_EXCEPTION);
    }

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

至此mDataSourceSupplier才浮出水面慕购,最后實現(xiàn)了get方法正是獲取圖片數(shù)據(jù)請求的方法:

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

繼續(xù)追蹤:

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

繼續(xù)追蹤submitFetchRequest:

private <T> DataSource<CloseableReference<T>> submitFetchRequest(
      Producer<CloseableReference<T>> producerSequence,
      ImageRequest imageRequest,
      ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit,
      Object callerContext) {
    final RequestListener requestListener = getRequestListenerForRequest(imageRequest);

    try {
      ImageRequest.RequestLevel lowestPermittedRequestLevel =
          ImageRequest.RequestLevel.getMax(
              imageRequest.getLowestPermittedRequestLevel(),
              lowestPermittedRequestLevelOnSubmit);
      SettableProducerContext settableProducerContext = new SettableProducerContext(
          imageRequest,
          generateUniqueFutureId(),
          requestListener,
          callerContext,
          lowestPermittedRequestLevel,
        /* isPrefetch */ false,
          imageRequest.getProgressiveRenderingEnabled() ||
              imageRequest.getMediaVariations() != null ||
              !UriUtil.isNetworkUri(imageRequest.getSourceUri()),
          imageRequest.getPriority());
      return CloseableProducerToDataSourceAdapter.create(
          producerSequence,
          settableProducerContext,
          requestListener);
    } catch (Exception exception) {
      return DataSources.immediateFailedDataSource(exception);
    }
  }

繼續(xù)追蹤CloseableProducerToDataSourceAdapter.create

public static <T> DataSource<T> create(
      Producer<T> producer,
      SettableProducerContext settableProducerContext,
      RequestListener listener) {
    return new ProducerToDataSourceAdapter<T>(
        producer,
        settableProducerContext,
        listener);
  }

繼續(xù)

protected AbstractProducerToDataSourceAdapter(
      Producer<T> producer,
      SettableProducerContext settableProducerContext,
      RequestListener requestListener) {
    mSettableProducerContext = settableProducerContext;
    mRequestListener = requestListener;
    mRequestListener.onRequestStart(
        settableProducerContext.getImageRequest(),
        mSettableProducerContext.getCallerContext(),
        mSettableProducerContext.getId(),
        mSettableProducerContext.isPrefetch());
    producer.produceResults(createConsumer(), settableProducerContext);
  }

重點在producer.produceResults聊疲,但producer是什么呢?

public Producer<CloseableReference<PooledByteBuffer>>
  getNetworkFetchEncodedImageProducerSequence() {
    synchronized (this) {
      if (mNetworkEncodedImageProducerSequence == null) {
        mNetworkEncodedImageProducerSequence = new RemoveImageTransformMetaDataProducer(
            getBackgroundNetworkFetchToEncodedMemorySequence());
      }
    }
    return mNetworkEncodedImageProducerSequence;
  }

一直追蹤沪悲,發(fā)現(xiàn)具體請求網(wǎng)絡(luò)數(shù)據(jù)在NetworkFetchProducer這個類,其中有一個mNetworkFetcher.fetch方法:

@Override
  public void produceResults(Consumer<EncodedImage> consumer, ProducerContext context) {
    context.getListener()
        .onProducerStart(context.getId(), PRODUCER_NAME);
    final FetchState fetchState = mNetworkFetcher.createFetchState(consumer, context);
    mNetworkFetcher.fetch(
        fetchState, new NetworkFetcher.Callback() {
          @Override
          public void onResponse(InputStream response, int responseLength) throws IOException {
            NetworkFetchProducer.this.onResponse(fetchState, response, responseLength);
          }

          @Override
          public void onFailure(Throwable throwable) {
            NetworkFetchProducer.this.onFailure(fetchState, throwable);
          }

          @Override
          public void onCancellation() {
            NetworkFetchProducer.this.onCancellation(fetchState);
          }
        });
  }

看一下mNetworkFetcher.createFetchState方法做什么工作:

我們發(fā)現(xiàn)获洲,有兩個類實現(xiàn)了這個接口,分別是HttpUrlConnectionNetworkFetcher和OkHttpNetworkFetcher,走到這一步就很明顯了:Fresco加載圖片用的是okhttp和httpurlconnection。

讓我們看一下Fresco的okhttp加載數(shù)據(jù)實現(xiàn):

protected void fetchWithRequest(
      final OkHttpNetworkFetchState fetchState,
      final Callback callback,
      final Request request) {
    final Call call = mCallFactory.newCall(request);

    fetchState.getContext().addCallbacks(
        new BaseProducerContextCallbacks() {
          @Override
          public void onCancellationRequested() {
            if (Looper.myLooper() != Looper.getMainLooper()) {
              call.cancel();
            } else {
              mCancellationExecutor.execute(new Runnable() {
                @Override public void run() {
                  call.cancel();
                }
              });
            }
          }
        });

    call.enqueue(
        new okhttp3.Callback() {
          @Override
          public void onResponse(Call call, Response response) throws IOException {
            fetchState.responseTime = SystemClock.elapsedRealtime();
            final ResponseBody body = response.body();
            try {
              if (!response.isSuccessful()) {
                handleException(
                    call,
                    new IOException("Unexpected HTTP code " + response),
                    callback);
                return;
              }

              BytesRange responseRange =
                  BytesRange.fromContentRangeHeader(response.header("Content-Range"));
              if (responseRange != null) {
                fetchState.setResponseBytesRange(responseRange);
                fetchState.setOnNewResultStatusFlags(Consumer.IS_PARTIAL_RESULT);
              }

              long contentLength = body.contentLength();
              if (contentLength < 0) {
                contentLength = 0;
              }
              callback.onResponse(body.byteStream(), (int) contentLength);
            } catch (Exception e) {
              handleException(call, e, callback);
            } finally {
              try {
                body.close();
              } catch (Exception e) {
                FLog.w(TAG, "Exception when closing response body", e);
              }
            }
          }

          @Override
          public void onFailure(Call call, IOException e) {
            handleException(call, e, callback);
          }
        });
  }

而Fresco的httpurlconnection實現(xiàn):

void fetchSync(FetchState fetchState, Callback callback) {
    HttpURLConnection connection = null;
    InputStream is = null;
    try {
      connection = downloadFrom(fetchState.getUri(), MAX_REDIRECTS);

      if (connection != null) {
        is = connection.getInputStream();
        callback.onResponse(is, -1);
      }
    } catch (IOException e) {
      callback.onFailure(e);
    } finally {
      if (is != null) {
        try {
          is.close();
        } catch (IOException e) {
          // do nothing and ignore the IOException here
        }
      }
      if (connection != null) {
        connection.disconnect();
      }
    }

  }

  private HttpURLConnection downloadFrom(Uri uri, int maxRedirects) throws IOException {
    HttpURLConnection connection = openConnectionTo(uri);
    int responseCode = connection.getResponseCode();

    if (isHttpSuccess(responseCode)) {
        return connection;

    } else if (isHttpRedirect(responseCode)) {
        String nextUriString = connection.getHeaderField("Location");
        connection.disconnect();

        Uri nextUri = (nextUriString == null) ? null : Uri.parse(nextUriString);
        String originalScheme = uri.getScheme();

        if (maxRedirects > 0 && nextUri != null && !nextUri.getScheme().equals(originalScheme)) {
          return downloadFrom(nextUri, maxRedirects - 1);
        } else {
          String message = maxRedirects == 0
              ? error("URL %s follows too many redirects", uri.toString())
              : error("URL %s returned %d without a valid redirect", uri.toString(), responseCode);
          throw new IOException(message);
        }

    } else {
        connection.disconnect();
        throw new IOException(String
            .format("Image URL %s returned HTTP code %d", uri.toString(), responseCode));
    }
  }

至此我們已經(jīng)清楚殿如,F(xiàn)resco對圖片的加載,那么他是怎么回調(diào)的呢贡珊?

可以看到

 mNetworkFetcher.fetch(
        fetchState, new NetworkFetcher.Callback() {
          @Override
          public void onResponse(InputStream response, int responseLength) throws IOException {
            NetworkFetchProducer.this.onResponse(fetchState, response, responseLength);
          }

          @Override
          public void onFailure(Throwable throwable) {
            NetworkFetchProducer.this.onFailure(fetchState, throwable);
          }

          @Override
          public void onCancellation() {
            NetworkFetchProducer.this.onCancellation(fetchState);
          }
        });

在NetworkFetchProducer中就實現(xiàn)了回調(diào),這仍然處于子線程涉馁,那么看一看數(shù)據(jù)的回調(diào):

private void onResponse(
      FetchState fetchState,
      InputStream responseData,
      int responseContentLength)
      throws IOException {
    final PooledByteBufferOutputStream pooledOutputStream;
    if (responseContentLength > 0) {
      pooledOutputStream = mPooledByteBufferFactory.newOutputStream(responseContentLength);
    } else {
      pooledOutputStream = mPooledByteBufferFactory.newOutputStream();
    }
    final byte[] ioArray = mByteArrayPool.get(READ_SIZE);
    try {
      int length;
      while ((length = responseData.read(ioArray)) >= 0) {
        if (length > 0) {
          pooledOutputStream.write(ioArray, 0, length);
          maybeHandleIntermediateResult(pooledOutputStream, fetchState);
          float progress = calculateProgress(pooledOutputStream.size(), responseContentLength);

          //獲取數(shù)據(jù)的回調(diào)就在這里
          fetchState.getConsumer().onProgressUpdate(progress);

        }
      }
      mNetworkFetcher.onFetchCompletion(fetchState, pooledOutputStream.size());
      handleFinalResult(pooledOutputStream, fetchState);
    } finally {
      mByteArrayPool.release(ioArray);
      pooledOutputStream.close();
    }
  }

private void handleFinalResult(
      PooledByteBufferOutputStream pooledOutputStream,
      FetchState fetchState) {
    Map<String, String> extraMap = getExtraMap(fetchState, pooledOutputStream.size());
    ProducerListener listener = fetchState.getListener();
    listener.onProducerFinishWithSuccess(fetchState.getId(), PRODUCER_NAME, extraMap);
    listener.onUltimateProducerReached(fetchState.getId(), PRODUCER_NAME, true);
    notifyConsumer(
        pooledOutputStream,
        Consumer.IS_LAST | fetchState.getOnNewResultStatusFlags(),
        fetchState.getResponseBytesRange(),
        fetchState.getConsumer());
  }

  private void notifyConsumer(
      PooledByteBufferOutputStream pooledOutputStream,
      @Consumer.Status int status,
      @Nullable BytesRange responseBytesRange,
      Consumer<EncodedImage> consumer) {
    CloseableReference<PooledByteBuffer> result =
        CloseableReference.of(pooledOutputStream.toByteBuffer());
    EncodedImage encodedImage = null;
    try {
      encodedImage = new EncodedImage(result);
      encodedImage.setBytesRange(responseBytesRange);
      encodedImage.parseMetaData();
      //回調(diào)新結(jié)果
      consumer.onNewResult(encodedImage, status);
    } finally {
      EncodedImage.closeSafely(encodedImage);
      CloseableReference.closeSafely(result);
    }
  }

這里一直使用consumer.onProgressUpdate和consumer.onNewResult回調(diào),在AbstractProducerToDataSourceAdapter類里面有具體實現(xiàn):

private Consumer<T> createConsumer() {
    return new BaseConsumer<T>() {
      @Override
      protected void onNewResultImpl(@Nullable T newResult, @Status int status) {
        AbstractProducerToDataSourceAdapter.this.onNewResultImpl(newResult, status);
      }

      @Override
      protected void onFailureImpl(Throwable throwable) {
        AbstractProducerToDataSourceAdapter.this.onFailureImpl(throwable);
      }

      @Override
      protected void onCancellationImpl() {
        AbstractProducerToDataSourceAdapter.this.onCancellationImpl();
      }

      @Override
      protected void onProgressUpdateImpl(float progress) {
        AbstractProducerToDataSourceAdapter.this.setProgress(progress);
      }
    };
  }

那么在來看一下AbstractProducerToDataSourceAdapter中這些回調(diào)處理了哪些事務(wù):

protected void onNewResultImpl(@Nullable T result, int status) {
    boolean isLast = BaseConsumer.isLast(status);
    if (super.setResult(result, isLast)) {
      if (isLast) {
        mRequestListener.onRequestSuccess(
            mSettableProducerContext.getImageRequest(),
            mSettableProducerContext.getId(),
            mSettableProducerContext.isPrefetch());
      }
    }
  }

  private void onFailureImpl(Throwable throwable) {
    if (super.setFailure(throwable)) {
      mRequestListener.onRequestFailure(
          mSettableProducerContext.getImageRequest(),
          mSettableProducerContext.getId(),
          throwable,
          mSettableProducerContext.isPrefetch());
    }
  }

由上述代碼可知首先它們執(zhí)行了一個super.setResult和mRequestListener.onRequestSuccess门岔;
其中發(fā)現(xiàn)mResquestListener其實是由開發(fā)者自己設(shè)置的listener監(jiān)聽數(shù)據(jù)變化:最終由mRequestListener.onRequestSuccess接受業(yè)務(wù)執(zhí)行回調(diào),而mRequestListener的具體實現(xiàn)在ForwardingRequestListener類中,而我們現(xiàn)在具體看super.setResult中的邏輯:

protected boolean setResult(@Nullable T value, boolean isLast) {
    boolean result = setResultInternal(value, isLast);
    if (result) {
      notifyDataSubscribers();
    }
    return result;
  }

private boolean setResultInternal(@Nullable T value, boolean isLast) {
    T resultToClose = null;
    try {
      synchronized (this) {
        if (mIsClosed || mDataSourceStatus != DataSourceStatus.IN_PROGRESS) {
          resultToClose = value;
          return false;
        } else {
          if (isLast) {
            mDataSourceStatus = DataSourceStatus.SUCCESS;
            mProgress = 1;
          }
          if (mResult != value) {
            resultToClose = mResult;
            mResult = value;
          }
          return true;
        }
      }
    } finally {
      if (resultToClose != null) {
        closeResult(resultToClose);
      }
    }
  }

由上述代碼知道烤送,在數(shù)據(jù)加載完畢之后會返回true寒随,然后執(zhí)行notifyDataSubscribers,這個函數(shù)明顯是通知所有訂閱者狀態(tài)發(fā)生改變:


  @Override
  public void subscribe(final DataSubscriber<T> dataSubscriber, final Executor executor) {
    Preconditions.checkNotNull(dataSubscriber);
    Preconditions.checkNotNull(executor);
    boolean shouldNotify;

    synchronized(this) {
      if (mIsClosed) {
        return;
      }

      if (mDataSourceStatus == DataSourceStatus.IN_PROGRESS) {
        mSubscribers.add(Pair.create(dataSubscriber, executor));
      }

      shouldNotify = hasResult() || isFinished() || wasCancelled();
    }

    if (shouldNotify) {
      notifyDataSubscriber(dataSubscriber, executor, hasFailed(), wasCancelled());
    }
  }

private void notifyDataSubscribers() {
    final boolean isFailure = hasFailed();
    final boolean isCancellation = wasCancelled();
    for (Pair<DataSubscriber<T>, Executor> pair : mSubscribers) {
      notifyDataSubscriber(pair.first, pair.second, isFailure, isCancellation);
    }
  }

private void notifyDataSubscriber(
      final DataSubscriber<T> dataSubscriber,
      final Executor executor,
      final boolean isFailure,
      final boolean isCancellation) {
    executor.execute(
        new Runnable() {
          @Override
          public void run() {
            if (isFailure) {
              dataSubscriber.onFailure(AbstractDataSource.this);
            } else if (isCancellation) {
              dataSubscriber.onCancellation(AbstractDataSource.this);
            } else {
              dataSubscriber.onNewResult(AbstractDataSource.this);
            }
          }
        });
  }

protected void notifyProgressUpdate() {
    for (Pair<DataSubscriber<T>, Executor> pair : mSubscribers) {
      final DataSubscriber<T> subscriber = pair.first;
      Executor executor = pair.second;
      executor.execute(
          new Runnable() {
            @Override
            public void run() {
              subscriber.onProgressUpdate(AbstractDataSource.this);
            }
          });
    }
  }

這里面mSubscribers.add(Pair.create(dataSubscriber, executor));將每個subcriber與一個Executor通過一個Pair對象(相當(dāng)于一個鍵值對)綁定在一起,那么這個executor是執(zhí)行任務(wù)線程是主線程還是子線程呢:

這里需要回一下submitRequest這個函數(shù),在getDataSource之后妻往,它編創(chuàng)建了一個Subcriber并執(zhí)行了Subcribe方法:

protected void submitRequest() {
    final T closeableImage = getCachedImage();
    if (closeableImage != null) {
      mDataSource = null;
      mIsRequestSubmitted = true;
      mHasFetchFailed = false;
      mEventTracker.recordEvent(Event.ON_SUBMIT_CACHE_HIT);
      getControllerListener().onSubmit(mId, mCallerContext);
      onNewResultInternal(mId, mDataSource, closeableImage, 1.0f, true, true);
      return;
    }
    mEventTracker.recordEvent(Event.ON_DATASOURCE_SUBMIT);
    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();
    //創(chuàng)建訂閱者 并執(zhí)行回調(diào)
    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();
            float progress = dataSource.getProgress();
            T image = dataSource.getResult();
            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<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);
  }

可以在上述代碼中看到mDataSource.subscribe中傳遞一個mUiThreadImmediateExecutor;有此名稱可見逢防,它的任務(wù)執(zhí)行線程是主線程,那么他在哪兒初始化的呢?

public PipelineDraweeControllerBuilderSupplier(
      Context context,
      ImagePipelineFactory imagePipelineFactory,
      Set<ControllerListener> boundControllerListeners,
      @Nullable DraweeConfig draweeConfig) {
    mContext = context;
    mImagePipeline = imagePipelineFactory.getImagePipeline();

    if (draweeConfig != null && draweeConfig.getPipelineDraweeControllerFactory() != null) {
      mPipelineDraweeControllerFactory = draweeConfig.getPipelineDraweeControllerFactory();
    } else {
      mPipelineDraweeControllerFactory = new PipelineDraweeControllerFactory();
    }
    mPipelineDraweeControllerFactory.init(
        context.getResources(),
        DeferredReleaser.getInstance(),
        imagePipelineFactory.getAnimatedDrawableFactory(context),
        UiThreadImmediateExecutorService.getInstance(),
        mImagePipeline.getBitmapMemoryCache(),
        draweeConfig != null
            ? draweeConfig.getCustomDrawableFactories()
            : null,
        draweeConfig != null
            ? draweeConfig.getDebugOverlayEnabledSupplier()
            : null);
    mBoundControllerListeners = boundControllerListeners;
  }

在PipelineDraweeControllerBuilderSupplier構(gòu)造函數(shù)中蒲讯,mPipelineDraweeControllerFactory.init第四個參數(shù)UiThreadImmediateExecutorService.getInstance()的靜態(tài)實例方法作為參數(shù)傳遞;一起來看一下UiThreadImmediateExecutorService類的實現(xiàn):

public class UiThreadImmediateExecutorService extends HandlerExecutorServiceImpl {
  private static UiThreadImmediateExecutorService sInstance = null;

  private UiThreadImmediateExecutorService() {
    super(new Handler(Looper.getMainLooper()));
  }

  public static UiThreadImmediateExecutorService getInstance() {
    if (sInstance == null) {
      sInstance = new UiThreadImmediateExecutorService();
    }
    return sInstance;
  }

  @Override
  public void execute(Runnable command) {
    if (isHandlerThread()) {
      command.run();
    } else {
      super.execute(command);
    }
  }
}

可以看到灰署,它的構(gòu)造函數(shù)這里傳遞了一個主線程的handler進去判帮,到這里就大概明白了它是通過handler郵寄runnable從而達(dá)到線程切換:

public class HandlerExecutorServiceImpl extends AbstractExecutorService
    implements HandlerExecutorService {

  private final Handler mHandler;

  public HandlerExecutorServiceImpl(Handler handler) {
    mHandler = handler;
  }

  ......

  @Override
  public void execute(Runnable command) {
    mHandler.post(command);
  }
}

所以回到subcriber中,可以知道一下這段BaseDataSubscriber的具體實現(xiàn)是在主線程執(zhí)行的:

//創(chuàng)建訂閱者 并執(zhí)行回調(diào)
    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();
            float progress = dataSource.getProgress();
            T image = dataSource.getResult();
            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<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);
          }
        };

最后成功回調(diào)onNewResultInternal方法完成圖片內(nèi)存緩存與顯示并釋放資源:

private void onNewResultInternal(
      String id,
      DataSource<T> 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;
        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);
      }
    }
  }

至此溉箕,fresco加載圖片結(jié)束晦墙。

最后的GenericDraweeHierarchy轉(zhuǎn)換圖像可以看一下

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市肴茄,隨后出現(xiàn)的幾起案子晌畅,更是在濱河造成了極大的恐慌,老刑警劉巖寡痰,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抗楔,死亡現(xiàn)場離奇詭異,居然都是意外死亡拦坠,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來畦幢,“玉大人庸蔼,你說我怎么就攤上這事∠” “怎么了勺良?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長骄噪。 經(jīng)常有香客問我尚困,道長,這世上最難降的妖魔是什么链蕊? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任尾组,我火速辦了婚禮,結(jié)果婚禮上示弓,老公的妹妹穿的比我還像新娘讳侨。我一直安慰自己,他們只是感情好奏属,可當(dāng)我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布跨跨。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪勇婴。 梳的紋絲不亂的頭發(fā)上忱嘹,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天,我揣著相機與錄音耕渴,去河邊找鬼拘悦。 笑死,一個胖子當(dāng)著我的面吹牛橱脸,可吹牛的內(nèi)容都是我干的础米。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼添诉,長吁一口氣:“原來是場噩夢啊……” “哼屁桑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起栏赴,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤蘑斧,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后须眷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體竖瘾,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年花颗,在試婚紗的時候發(fā)現(xiàn)自己被綠了准浴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡捎稚,死狀恐怖乐横,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情今野,我是刑警寧澤葡公,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站条霜,受9級特大地震影響催什,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宰睡,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一蒲凶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拆内,春花似錦旋圆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搀矫。三九已至,卻和暖如春刻肄,著一層夾襖步出監(jiān)牢的瞬間瓤球,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工敏弃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留卦羡,地道東北人。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓麦到,卻偏偏與公主長得像绿饵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子隅要,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,325評論 25 707
  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 29,418評論 8 265
  • Fresco簡單的使用—SimpleDraweeView 百學(xué)須先立志—學(xué)前須知: 在我們平時加載圖片(不管是下載...
    天天大保建閱讀 3,432評論 0 8
  • 周五的籃球賽結(jié)束了 周六的英語六級考試也過去了 周日泡了一天的圖書館不得不承認(rèn)效率特別低 好在終于迎來周一下午的實...
    菀卿閱讀 164評論 0 0
  • 2018.7.10星期二 本來說是放假了可以帶寶貝們出去旅游,去寶爸的目的地董济,可是寶貝們都不去步清。二寶反而對...
    石卓航石雨卓家長閱讀 172評論 0 2