Fresco源碼分析(二)

先看Imagepipeline:

Image pipeline 負(fù)責(zé)完成加載圖像脯倒,變成Android設(shè)備可呈現(xiàn)的形式所要做的每個事情星虹。
大致流程如下:

  • 檢查內(nèi)存緩存,如有除师,返回
  • 后臺線程開始后續(xù)工作
  • 檢查是否在未解碼內(nèi)存緩存中地回。如有扁远,解碼,變換刻像,返回畅买,然后緩存到內(nèi)存緩存中。
  • 檢查是否在磁盤緩存中细睡,如果有谷羞,變換,返回溜徙。緩存到未解碼緩存和內(nèi)存緩存中湃缎。
  • 從網(wǎng)絡(luò)或者本地加載。加載完成后蠢壹,解碼嗓违,變換,返回图贸。存到各個緩存中蹂季。

總之你認(rèn)為是個策略工廠

package com.facebook.imagepipeline.core;

import *

/**
 * The entry point for the image pipeline.
 */
@ThreadSafe
public class ImagePipeline {
  private static final CancellationException PREFETCH_EXCEPTION =
      new CancellationException("Prefetching is not enabled");

  private final ProducerSequenceFactory mProducerSequenceFactory;
  private final RequestListener mRequestListener;
  private final Supplier<Boolean> mIsPrefetchEnabledSupplier;
  private final MemoryCache<CacheKey, CloseableImage> mBitmapMemoryCache;
  private final MemoryCache<CacheKey, PooledByteBuffer> mEncodedMemoryCache;
  private final BufferedDiskCache mMainBufferedDiskCache;
  private final BufferedDiskCache mSmallImageBufferedDiskCache;
  private final CacheKeyFactory mCacheKeyFactory;
  private final ThreadHandoffProducerQueue mThreadHandoffProducerQueue;
  private AtomicLong mIdCounter;

  public ImagePipeline(
      ProducerSequenceFactory producerSequenceFactory, // 消費(fèi)和生產(chǎn)者模式,這個會創(chuàng)建網(wǎng)絡(luò)請求片段序列
      Set<RequestListener> requestListeners, // 這貨就是最后疏日,下載完圖片偿洁,通過消費(fèi)者,最后回掉用的接口
      Supplier<Boolean> isPrefetchEnabledSupplier,
      MemoryCache<CacheKey, CloseableImage> bitmapMemoryCache, // 緩存1級
      MemoryCache<CacheKey, PooledByteBuffer> encodedMemoryCache, // 緩存2級
      BufferedDiskCache mainBufferedDiskCache, // Frescon 支持大圖和小圖區(qū)別對待沟优,分開buff和toDisk父能,默認(rèn)都是這個
      BufferedDiskCache smallImageBufferedDiskCache,// 小圖
      CacheKeyFactory cacheKeyFactory, // 默認(rèn)的key-value工廠
      ThreadHandoffProducerQueue threadHandoffProducerQueue) { // 生產(chǎn)者隊列,用于在pause關(guān)閉資源
    mIdCounter = new AtomicLong(); // 為這個ImagePiple打一個獨特內(nèi)存id
    mProducerSequenceFactory = producerSequenceFactory;
    mRequestListener = new ForwardingRequestListener(requestListeners);// 這個是回掉接口包裝
    mIsPrefetchEnabledSupplier = isPrefetchEnabledSupplier;
    mBitmapMemoryCache = bitmapMemoryCache;
    mEncodedMemoryCache = encodedMemoryCache;
    mMainBufferedDiskCache = mainBufferedDiskCache;
    mSmallImageBufferedDiskCache = smallImageBufferedDiskCache;
    mCacheKeyFactory = cacheKeyFactory;
    mThreadHandoffProducerQueue = threadHandoffProducerQueue;
  }

  private String generateUniqueFutureId() {
    return String.valueOf(mIdCounter.getAndIncrement());
  }

  /**
   * Returns a DataSource supplier that will on get submit the request for execution and return a
   * DataSource representing the pending results of the task.
   * 完成request净神,帶bitmapCacheOnly這個flag策略,加載圖片來源
   */
  public Supplier<DataSource<CloseableReference<CloseableImage>>> getDataSourceSupplier(
      final ImageRequest imageRequest,
      final Object callerContext,
      final boolean bitmapCacheOnly) {
    return new Supplier<DataSource<CloseableReference<CloseableImage>>>() {
      @Override
      public DataSource<CloseableReference<CloseableImage>> get() {
        if (bitmapCacheOnly) {
          return fetchImageFromBitmapCache(imageRequest, callerContext);
        } else {
          return fetchDecodedImage(imageRequest, callerContext);
        }
      }
    };
  }

  /**
   * Returns a DataSource supplier that will on get submit the request for execution and return a
   * DataSource representing the pending results of the task.
   * 完成request溉委,加載圖片來源鹃唯,磁盤或者網(wǎng)絡(luò)
   */
  public Supplier<DataSource<CloseableReference<PooledByteBuffer>>>
      getEncodedImageDataSourceSupplier(
          final ImageRequest imageRequest,
          final Object callerContext) {
    return new Supplier<DataSource<CloseableReference<PooledByteBuffer>>>() {
      @Override
      public DataSource<CloseableReference<PooledByteBuffer>> get() {
        return fetchEncodedImage(imageRequest, callerContext);
      }
    };
  }

  /**
   * Submits a request for bitmap cache lookup.
   * 完成request,加載圖片來源 圖片緩存
   */
  public DataSource<CloseableReference<CloseableImage>> fetchImageFromBitmapCache(
      ImageRequest imageRequest,
      Object callerContext) {
    try {
      Producer<CloseableReference<CloseableImage>> producerSequence =
          mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
      return submitFetchRequest(
          producerSequence,
          imageRequest,
          ImageRequest.RequestLevel.BITMAP_MEMORY_CACHE, //     BITMAP_MEMORY_CACHE(4); 這個等級是Bitmap caching
          callerContext);
    } catch (Exception exception) {
      return DataSources.immediateFailedDataSource(exception);
    }
  }

  /**
   * Submits a request for execution and returns a DataSource representing the pending decoded
   * image(s). 完成request瓣喊,加載圖片來源網(wǎng)絡(luò)或者磁盤
   * <p>The returned DataSource must be closed once the client has finished with it.
   */
  public DataSource<CloseableReference<CloseableImage>> fetchDecodedImage(
      ImageRequest imageRequest,
      Object callerContext) {
    try {
      Producer<CloseableReference<CloseableImage>> producerSequence =
          mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
      return submitFetchRequest(
          producerSequence,
          imageRequest,
          ImageRequest.RequestLevel.FULL_FETCH, // 這個等級 Fetch (from the network or local storage) 
          callerContext);
    } catch (Exception exception) {
      return DataSources.immediateFailedDataSource(exception);
    }
  }

  /**
   * Submits a request for execution and returns a DataSource representing the pending encoded
   * image(s).
   * 最終要調(diào)這個Submits
   */
  public DataSource<CloseableReference<PooledByteBuffer>> fetchEncodedImage(
      ImageRequest imageRequest,
      Object callerContext) {
    Preconditions.checkNotNull(imageRequest.getSourceUri());
    try {
      Producer<CloseableReference<PooledByteBuffer>> producerSequence =
          mProducerSequenceFactory.getEncodedImageProducerSequence(imageRequest); // 這個很重要了坡慌,NetWork請求client在這個里面準(zhǔn)備好
      // The resize options are used to determine whether images are going to be downsampled during
      // decode or not. For the case where the image has to be downsampled and it's a local image it
      // will be kept as a FileInputStream until decoding instead of reading it in memory. Since
      // this method returns an encoded image, it should always be read into memory. Therefore, the
      // resize options are ignored to avoid treating the image as if it was to be downsampled
      // during decode.
      if (imageRequest.getResizeOptions() != null) {
        imageRequest = ImageRequestBuilder.fromRequest(imageRequest)
            .setResizeOptions(null)
            .build();
      }
      return submitFetchRequest(
          producerSequence,
          imageRequest,
          ImageRequest.RequestLevel.FULL_FETCH,
          callerContext); // 執(zhí)行生產(chǎn)者消費(fèi)者 從這里開始了
    } catch (Exception exception) {
      return DataSources.immediateFailedDataSource(exception);
    }
  }

  public DataSource<Void> prefetchToBitmapCache(
      ImageRequest imageRequest,
      Object callerContext) {
    if (!mIsPrefetchEnabledSupplier.get()) {
      return DataSources.immediateFailedDataSource(PREFETCH_EXCEPTION);
    }
    try {
      Producer<Void> producerSequence =
          mProducerSequenceFactory.getDecodedImagePrefetchProducerSequence(imageRequest);
      return submitPrefetchRequest(
          producerSequence,
          imageRequest,
          ImageRequest.RequestLevel.FULL_FETCH,
          callerContext,
          Priority.MEDIUM);
    } catch (Exception exception) {
      return DataSources.immediateFailedDataSource(exception);
    }
  }

  public DataSource<Void> prefetchToDiskCache(
      ImageRequest imageRequest,
      Object callerContext,
      Priority priority) {
    if (!mIsPrefetchEnabledSupplier.get()) {
      return DataSources.immediateFailedDataSource(PREFETCH_EXCEPTION);
    }
    try {
      Producer<Void> producerSequence =
          mProducerSequenceFactory.getEncodedImagePrefetchProducerSequence(imageRequest);
      return submitPrefetchRequest(
          producerSequence,
          imageRequest,
          ImageRequest.RequestLevel.FULL_FETCH,
          callerContext,
          priority);
    } catch (Exception exception) {
      return DataSources.immediateFailedDataSource(exception);
    }
  }

     .........


  private <T> DataSource<CloseableReference<T>> submitFetchRequest(
      Producer<CloseableReference<T>> producerSequence,
      ImageRequest imageRequest,
      ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit,
      Object callerContext) {
    try {
      ImageRequest.RequestLevel lowestPermittedRequestLevel =
          ImageRequest.RequestLevel.getMax(
              imageRequest.getLowestPermittedRequestLevel(),
              lowestPermittedRequestLevelOnSubmit);
      SettableProducerContext settableProducerContext = new SettableProducerContext(// 創(chuàng)建一個上下文對象,如同Android:Context
          imageRequest,
          generateUniqueFutureId(),
          mRequestListener,
          callerContext,
          lowestPermittedRequestLevel,
        /* isPrefetch */ false,
          imageRequest.getProgressiveRenderingEnabled() ||
              !UriUtil.isNetworkUri(imageRequest.getSourceUri()),
          imageRequest.getPriority());
      return CloseableProducerToDataSourceAdapter.create( //生產(chǎn)者數(shù)據(jù)源開始
          producerSequence,
          settableProducerContext,
          mRequestListener);
    } catch (Exception exception) {
      return DataSources.immediateFailedDataSource(exception);
    }
  }

  private DataSource<Void> submitPrefetchRequest( // 這個就是從內(nèi)存拿策略和上面差不多藻三,介紹上面那個洪橘,不同就是生產(chǎn)者不同
      Producer<Void> producerSequence,
      ImageRequest imageRequest,
      ImageRequest.RequestLevel lowestPermittedRequestLevelOnSubmit,
      Object callerContext,
      Priority priority) {
    try {
      ImageRequest.RequestLevel lowestPermittedRequestLevel =
          ImageRequest.RequestLevel.getMax(
              imageRequest.getLowestPermittedRequestLevel(),
              lowestPermittedRequestLevelOnSubmit);
      SettableProducerContext settableProducerContext = new SettableProducerContext(
          imageRequest,
          generateUniqueFutureId(),
          mRequestListener,
          callerContext,
          lowestPermittedRequestLevel,
        /* isPrefetch */ true,
        /* isIntermediateResultExpected */ false,
          priority);
      return ProducerToDataSourceAdapter.create(
          producerSequence,
          settableProducerContext,
          mRequestListener);
    } catch (Exception exception) {
      return DataSources.immediateFailedDataSource(exception);
    }
  }

   ........

  public void pause() {
    mThreadHandoffProducerQueue.startQueueing();
  }

  public void resume() {
    mThreadHandoffProducerQueue.stopQueuing();
  }

  public boolean isPaused() {
    return mThreadHandoffProducerQueue.isQueueing();
  }

  /**
   * @return The CacheKeyFactory implementation used by ImagePipeline
   */
  public CacheKeyFactory getCacheKeyFactory() {
    return mCacheKeyFactory;
  }
}

在構(gòu)造函數(shù)中我們看到了mRequestListener = new ForwardingRequestListener(requestListeners);這貨就是提交給ImagePipleDraweeController中Listener跪者,基本無用,默認(rèn)requestListeners為null
流程:
AbstractDraweeController:sumbit() ===>PipelineDraweeController:getDataSource() ===> PipelineDraweeControllerBuilderSupplier === > ImagePipelineFactory === > ImagePipeline ===> ImagePipeline:getDataSourceSupplier() === >fetchDecodedImage() ===>ProducerSequenceFactory:getDecodedImageProducerSequence(imageRequest)處理,然后創(chuàng)建生產(chǎn)者和消費(fèi)者CloseableProducerToDataSourceAdapter:create() ===>線程等級為ProducerSequenceFactory.BackGroudTask執(zhí)行request
在介紹生產(chǎn)者之前熄求,先把ProducerSequenceFactory這個看了

  public Producer<CloseableReference<CloseableImage>> getDecodedImageProducerSequence(
      ImageRequest imageRequest) {
    Producer<CloseableReference<CloseableImage>> pipelineSequence =
        getBasicDecodedImageSequence(imageRequest);// 這里開始裝配
    if (imageRequest.getPostprocessor() != null) {// 判斷是否有后后處理器渣玲,默認(rèn)是沒有
      return getPostprocessorSequence(pipelineSequence);
    } else {
      return pipelineSequence;
    }
  }

關(guān)于后處理器: 完成特殊定制,就是你在下載完成后弟晚,這個圖片需要特殊要求和處理

Producer<CloseableReference<CloseableImage>> pipelineSequence = getBasicDecodedImageSequence(imageRequest);
 private Producer<CloseableReference<CloseableImage>> getBasicDecodedImageSequence(
      ImageRequest imageRequest) {
    Preconditions.checkNotNull(imageRequest);

    Uri uri = imageRequest.getSourceUri(); // setUrl時候構(gòu)造
    Preconditions.checkNotNull(uri, "Uri is null.");
    if (UriUtil.isNetworkUri(uri)) {
      return getNetworkFetchSequence(); // 網(wǎng)絡(luò)請求走這個
    } else if (UriUtil.isLocalFileUri(uri)) {
      if (MediaUtils.isVideo(MediaUtils.extractMime(uri.getPath()))) {
        return getLocalVideoFileFetchSequence();
      } else {
        return getLocalImageFileFetchSequence();
      }
    } else if (UriUtil.isLocalContentUri(uri)) {
      return getLocalContentUriFetchSequence();
    } else if (UriUtil.isLocalAssetUri(uri)) {
      return getLocalAssetFetchSequence();
    } else if (UriUtil.isLocalResourceUri(uri)) {
      return getLocalResourceFetchSequence();
    } else if (UriUtil.isDataUri(uri)) {
      return getDataFetchSequence();
    } else {
      String uriString = uri.toString();
      if (uriString.length() > 30) {
        uriString = uriString.substring(0, 30) + "...";
      }
      throw new RuntimeException("Unsupported uri scheme! Uri is: " + uriString);
    }
  }

其中大部分我們不關(guān)心忘衍,先找到核心請求,其它只是策略
getNetworkFetchSequence(); 不用看卿城,就這貨了枚钓。

/**
   * swallow result if prefetch -> bitmap cache get ->
   * background thread hand-off -> multiplex -> bitmap cache -> decode -> multiplex ->
   * encoded cache -> disk cache -> (webp transcode) -> network fetch.
   * 大致就是說,沒有緩存你就走disk瑟押,再沒有就network搀捷, multiplex是指多個request load 一起來,一樣的流程多望,因為是有multiplex嫩舟,所有同步方法
   */
  private synchronized Producer<CloseableReference<CloseableImage>> getNetworkFetchSequence() {
    if (mNetworkFetchSequence == null) {
      mNetworkFetchSequence =
          newBitmapCacheGetToDecodeSequence(getCommonNetworkFetchToEncodedMemorySequence());
    }
    return mNetworkFetchSequence;
  }

getCommonNetworkFetchToEncodedMemorySequence() 名字已經(jīng)暴露你了,什么XXX網(wǎng)絡(luò)片段請求

 /**
   * multiplex -> encoded cache -> disk cache -> (webp transcode) -> network fetch.
   */
  private synchronized Producer<EncodedImage> getCommonNetworkFetchToEncodedMemorySequence() {
    if (mCommonNetworkFetchToEncodedMemorySequence == null) {
      Producer<EncodedImage> inputProducer =
          newEncodedCacheMultiplexToTranscodeSequence(
              mProducerFactory.newNetworkFetchProducer(mNetworkFetcher));
      mCommonNetworkFetchToEncodedMemorySequence =
          ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer);

      if (mResizeAndRotateEnabledForNetwork && !mDownsampleEnabled) {
        mCommonNetworkFetchToEncodedMemorySequence =
            mProducerFactory.newResizeAndRotateProducer(
                mCommonNetworkFetchToEncodedMemorySequence);
      }
    }
    return mCommonNetworkFetchToEncodedMemorySequence;
  }

看重點便斥,其它亂78遭至壤,旋轉(zhuǎn)改變大小又重新干一個請求,這個不看枢纠。

Paste_Image.png

mNetworkFetcher這貨是真正底層網(wǎng)絡(luò)代碼了像街,默認(rèn)使用HttpUrlConnectionNetworkFetcher,HttpUrlConnection的bug已經(jīng)在4.3以后修復(fù)了晋渺,如果要定制okhttp镰绎,像作者一樣OkHttpNetworkFetcher,需要在Frescon初始化的時候注入:com.facebook.drawee.backends.pipeline.Fresco.initialize(this, OkHttpImagePipelineConfigFactory.newBuilder(this, new okhttp3.OkHttpClient()).build());

ProducerFactory.newAddImageTransformMetaDataProducer(inputProducer); 這貨就是消費(fèi)者添加圖片

 public static AddImageTransformMetaDataProducer newAddImageTransformMetaDataProducer(
      Producer<EncodedImage> inputProducer) {
    return new AddImageTransformMetaDataProducer(inputProducer);
  }

/**
 * Add image transform meta data producer
 *
 * <p>Extracts meta data from the results passed down from the next producer, and adds it to the
 * result that it returns to the consumer.
 */
public class AddImageTransformMetaDataProducer implements Producer<EncodedImage> {
  private final Producer<EncodedImage> mInputProducer;

  public AddImageTransformMetaDataProducer(Producer<EncodedImage> inputProducer) {
    mInputProducer = inputProducer;
  }

  @Override
  public void produceResults(Consumer<EncodedImage> consumer, ProducerContext context) {
    mInputProducer.produceResults(new AddImageTransformMetaDataConsumer(consumer), context);
  }

  private static class AddImageTransformMetaDataConsumer extends DelegatingConsumer<
      EncodedImage, EncodedImage> {

    private AddImageTransformMetaDataConsumer(Consumer<EncodedImage> consumer) {
      super(consumer);
    }

    @Override
    protected void onNewResultImpl(EncodedImage newResult, boolean isLast) {
      if (newResult == null) {
        getConsumer().onNewResult(null, isLast);
        return;
      }
      if (!EncodedImage.isMetaDataAvailable(newResult)) {
        newResult.parseMetaData();
      }
      getConsumer().onNewResult(newResult, isLast);
    }
  }
}

基本下載類

// 基本下載類木西,沒有什么特點
/**
 * Network fetcher that uses the simplest Android stack.
 *
 * <p> Apps requiring more sophisticated networking should implement their own
 * {@link NetworkFetcher}.
 */
public class HttpUrlConnectionNetworkFetcher extends BaseNetworkFetcher<FetchState> {

  private final ExecutorService mExecutorService;

  public HttpUrlConnectionNetworkFetcher() {
    this(Executors.newFixedThreadPool(NUM_NETWORK_THREADS));
  }

  @VisibleForTesting
  HttpUrlConnectionNetworkFetcher(ExecutorService executorService) {
    mExecutorService = executorService;
  }

  @Override
  public FetchState createFetchState(Consumer<EncodedImage> consumer, ProducerContext context) {
    return new FetchState(consumer, context);
  }

  @Override
  public void fetch(final FetchState fetchState, final Callback callback) {
    final Future<?> future = mExecutorService.submit(
        new Runnable() {
          @Override
          public void run() {
            fetchSync(fetchState, callback);
          }
        });
    fetchState.getContext().addCallbacks(
        new BaseProducerContextCallbacks() {
          @Override
          public void onCancellationRequested() {
            if (future.cancel(false)) {
              callback.onCancellation();
            }
          }
        });
  }

  @VisibleForTesting
  void fetchSync(FetchState fetchState, Callback callback) {
    HttpURLConnection connection = null;

    try {
      connection = downloadFrom(fetchState.getUri(), MAX_REDIRECTS);

      if (connection != null) {
        callback.onResponse(connection.getInputStream(), -1);
      }
    } catch (IOException e) {
      callback.onFailure(e);
    } finally {
      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));
    }
  }

  @VisibleForTesting
  static HttpURLConnection openConnectionTo(Uri uri) throws IOException {
    URL url = new URL(uri.toString());
    return (HttpURLConnection) url.openConnection();
  }
 ......

OkHttp下載介紹

// 下面是OkHttp称簿,使用了異步請求call.enqueue()...不知道童鞋,可以去百度下OkHttp畜伐,不難袖裕,也是建造者模式
public class OkHttpNetworkFetcher extends
    BaseNetworkFetcher<OkHttpNetworkFetcher.OkHttpNetworkFetchState> {

  public static class OkHttpNetworkFetchState extends FetchState {

    public OkHttpNetworkFetchState(
        Consumer<EncodedImage> consumer,
        ProducerContext producerContext) {
      super(consumer, producerContext);
    }
  }

  private final OkHttpClient mOkHttpClient;

  private Executor mCancellationExecutor;

  /**
   * @param okHttpClient client to use
   */
  public OkHttpNetworkFetcher(OkHttpClient okHttpClient) {
    mOkHttpClient = okHttpClient;
    mCancellationExecutor = okHttpClient.dispatcher().executorService();
  }

  @Override
  public OkHttpNetworkFetchState createFetchState(
      Consumer<EncodedImage> consumer,
      ProducerContext context) {
    return new OkHttpNetworkFetchState(consumer, context);
  }

  @Override
  public void fetch(final OkHttpNetworkFetchState fetchState, final Callback callback) {
    fetchState.submitTime = SystemClock.elapsedRealtime();
    final Uri uri = fetchState.getUri();
    final Request request = new Request.Builder()
        .cacheControl(new CacheControl.Builder().noStore().build())
        .url(uri.toString())
        .get()
        .build();
    final Call call = mOkHttpClient.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;
              }

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

newBitmapCacheGetToDecodeSequence這貨干緩存,前面干網(wǎng)絡(luò)請求恋捆。

  /**
   * Same as {@code newBitmapCacheGetToBitmapCacheSequence} but with an extra DecodeProducer.
   * @param inputProducer producer providing the input to the decode
   * @return bitmap cache get to decode sequence
   */
  private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToDecodeSequence(
      Producer<EncodedImage> inputProducer) {
    DecodeProducer decodeProducer = mProducerFactory.newDecodeProducer(inputProducer);
    return newBitmapCacheGetToBitmapCacheSequence(decodeProducer);
  }

DecodeProducer這貨images的包裝器照皆,build模式

/**
 * Decodes images.
 *
 * <p/> Progressive JPEGs are decoded progressively as new data arrives.
 */
public class DecodeProducer implements Producer<CloseableReference<CloseableImage>> {

  public static final String PRODUCER_NAME = "DecodeProducer";

  // keys for extra map
  private static final String BITMAP_SIZE_KEY = "bitmapSize";
  private static final String HAS_GOOD_QUALITY_KEY = "hasGoodQuality";
  private static final String IMAGE_TYPE_KEY = "imageType";
  private static final String IS_FINAL_KEY = "isFinal";

  private final ByteArrayPool mByteArrayPool;
  private final Executor mExecutor;
  private final ImageDecoder mImageDecoder;
  private final ProgressiveJpegConfig mProgressiveJpegConfig;
  private final Producer<EncodedImage> mInputProducer;
  private final boolean mDownsampleEnabled;
  private final boolean mDownsampleEnabledForNetwork;
  
  ........
}

里面有執(zhí)行器和byte數(shù)據(jù)池,Decoder
回歸主線:
newBitmapCacheGetToBitmapCacheSequence(decodeProducer);

/**
   * Bitmap cache get -> thread hand off -> multiplex -> bitmap cache
   * @param inputProducer producer providing the input to the bitmap cache
   * @return bitmap cache get to bitmap cache sequence
   */
  private Producer<CloseableReference<CloseableImage>> newBitmapCacheGetToBitmapCacheSequence(
      Producer<CloseableReference<CloseableImage>> inputProducer) {
    BitmapMemoryCacheProducer bitmapMemoryCacheProducer =
        mProducerFactory.newBitmapMemoryCacheProducer(inputProducer);
    BitmapMemoryCacheKeyMultiplexProducer bitmapKeyMultiplexProducer =
        mProducerFactory.newBitmapMemoryCacheKeyMultiplexProducer(bitmapMemoryCacheProducer);
    ThreadHandoffProducer<CloseableReference<CloseableImage>> threadHandoffProducer =
        mProducerFactory.newBackgroundThreadHandoffProducer(
            bitmapKeyMultiplexProducer,
            mThreadHandoffProducerQueue);
    return mProducerFactory.newBitmapMemoryCacheGetProducer(threadHandoffProducer);
  }

mProducerFactory.newBackgroundThreadHandoffProducer(bitmapKeyMultiplexProducer,mThreadHandoffProducerQueue);還記得前面有說ImagePipeline:mThreadHandoffProducerQueue么沸停,這貨維護(hù)請求資源膜毁,pause開打進(jìn)行釋放,resume反之
mProducerFactory.newBitmapMemoryCacheGetProducer(threadHandoffProducer);

  public BitmapMemoryCacheGetProducer newBitmapMemoryCacheGetProducer(
      Producer<CloseableReference<CloseableImage>> inputProducer) {
    return new BitmapMemoryCacheGetProducer(mBitmapMemoryCache, mCacheKeyFactory, inputProducer);
  }

最后塞到Cache中處理

/**
 * Bitmap memory cache producer that is read-only.
 */
public class BitmapMemoryCacheGetProducer extends BitmapMemoryCacheProducer {

  @VisibleForTesting static final String PRODUCER_NAME = "BitmapMemoryCacheGetProducer";

  public BitmapMemoryCacheGetProducer(
      MemoryCache<CacheKey, CloseableImage> memoryCache,
      CacheKeyFactory cacheKeyFactory,
      Producer<CloseableReference<CloseableImage>> inputProducer) {
    super(memoryCache, cacheKeyFactory, inputProducer);
  }

  @Override
  protected Consumer<CloseableReference<CloseableImage>> wrapConsumer(
      final Consumer<CloseableReference<CloseableImage>> consumer,
      final CacheKey cacheKey) {
    // since this cache is read-only, we can pass our consumer directly to the next producer
    return consumer;
  }

  @Override
  protected String getProducerName() {
    return PRODUCER_NAME;
  }

消費(fèi)者回掉在基類

/**
 * Memory cache producer for the bitmap memory cache.
 */
public class BitmapMemoryCacheProducer implements Producer<CloseableReference<CloseableImage>> {

  @VisibleForTesting static final String PRODUCER_NAME = "BitmapMemoryCacheProducer";
  @VisibleForTesting static final String VALUE_FOUND = "cached_value_found";

  private final MemoryCache<CacheKey, CloseableImage> mMemoryCache;
  private final CacheKeyFactory mCacheKeyFactory;
  private final Producer<CloseableReference<CloseableImage>> mInputProducer;

  public BitmapMemoryCacheProducer(
      MemoryCache<CacheKey, CloseableImage> memoryCache,
      CacheKeyFactory cacheKeyFactory,
      Producer<CloseableReference<CloseableImage>> inputProducer) {
    mMemoryCache = memoryCache;
    mCacheKeyFactory = cacheKeyFactory;
    mInputProducer = inputProducer;
  }

  @Override
  public void produceResults(
      final Consumer<CloseableReference<CloseableImage>> consumer,
      final ProducerContext producerContext) {

    final ProducerListener listener = producerContext.getListener();
    final String requestId = producerContext.getId();
    listener.onProducerStart(requestId, getProducerName());
    final ImageRequest imageRequest = producerContext.getImageRequest();
    final Object callerContext = producerContext.getCallerContext();
    final CacheKey cacheKey = mCacheKeyFactory.getBitmapCacheKey(imageRequest, callerContext);

    CloseableReference<CloseableImage> cachedReference = mMemoryCache.get(cacheKey);

    if (cachedReference != null) {
      boolean isFinal = cachedReference.get().getQualityInfo().isOfFullQuality();
      if (isFinal) {
        listener.onProducerFinishWithSuccess(
            requestId,
            getProducerName(),
            listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "true") : null);
        consumer.onProgressUpdate(1f);
      }
      consumer.onNewResult(cachedReference, isFinal);
      cachedReference.close();
      if (isFinal) {
        return;
      }
    }

    if (producerContext.getLowestPermittedRequestLevel().getValue() >=
        ImageRequest.RequestLevel.BITMAP_MEMORY_CACHE.getValue()) {
      listener.onProducerFinishWithSuccess(
          requestId,
          getProducerName(),
          listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
      consumer.onNewResult(null, true);
      return;
    }

    Consumer<CloseableReference<CloseableImage>> wrappedConsumer = wrapConsumer(consumer, cacheKey);
    listener.onProducerFinishWithSuccess(
        requestId,
        getProducerName(),
        listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
    mInputProducer.produceResults(wrappedConsumer, producerContext);
  }

  protected Consumer<CloseableReference<CloseableImage>> wrapConsumer(
      final Consumer<CloseableReference<CloseableImage>> consumer,
      final CacheKey cacheKey) {
    return new DelegatingConsumer<
        CloseableReference<CloseableImage>,
        CloseableReference<CloseableImage>>(consumer) {
      @Override
      public void onNewResultImpl(CloseableReference<CloseableImage> newResult, boolean isLast) {
        // ignore invalid intermediate results and forward the null result if last
        if (newResult == null) {
          if (isLast) {
            getConsumer().onNewResult(null, true);
          }
          return;
        }
        // stateful results cannot be cached and are just forwarded
        if (newResult.get().isStateful()) {
          getConsumer().onNewResult(newResult, isLast);
          return;
        }
        // if the intermediate result is not of a better quality than the cached result,
        // forward the already cached result and don't cache the new result.
        if (!isLast) {
          CloseableReference<CloseableImage> currentCachedResult = mMemoryCache.get(cacheKey);
          if (currentCachedResult != null) {
            try {
              QualityInfo newInfo = newResult.get().getQualityInfo();
              QualityInfo cachedInfo = currentCachedResult.get().getQualityInfo();
              if (cachedInfo.isOfFullQuality() || cachedInfo.getQuality() >= newInfo.getQuality()) {
                getConsumer().onNewResult(currentCachedResult, false);
                return;
              }
            } finally {
              CloseableReference.closeSafely(currentCachedResult);
            }
          }
        }
        // cache and forward the new result
        CloseableReference<CloseableImage> newCachedResult =
            mMemoryCache.cache(cacheKey, newResult);
        try {
          if (isLast) {
            getConsumer().onProgressUpdate(1f);
          }
          getConsumer().onNewResult(
              (newCachedResult != null) ? newCachedResult : newResult, isLast);
        } finally {
          CloseableReference.closeSafely(newCachedResult);
        }
      }
    };
  }

  protected String getProducerName() {
    return PRODUCER_NAME;
  }
}

produceResults()來自AbstractProducerToDataSourceAdapter(),往上追蹤這個方法來自ImagePipleine:submitFetchRequest():CloseableProducerToDataSourceAdapter:creat()進(jìn)行回掉
然后函數(shù)結(jié)尾的時候走mInputProducer.produceResults(wrappedConsumer, producerContext);
mInputProducer來自ImagePiple:fetchDecodedImage(): Producer<CloseableReference<CloseableImage>> producerSequence =
mProducerSequenceFactory.getDecodedImageProducerSequence(imageRequest);
生成:ThreadHandoffProducer

/**
 * Uses ExecutorService to move further computation to different thread
 */
public class ThreadHandoffProducer<T> implements Producer<T> {

  @VisibleForTesting
  protected static final String PRODUCER_NAME = "BackgroundThreadHandoffProducer";

  private final Producer<T> mInputProducer;
  private final ThreadHandoffProducerQueue mThreadHandoffProducerQueue;

  public ThreadHandoffProducer(final Producer<T> inputProducer,
                               final  ThreadHandoffProducerQueue inputThreadHandoffProducerQueue) {
    mInputProducer = Preconditions.checkNotNull(inputProducer);
    mThreadHandoffProducerQueue = inputThreadHandoffProducerQueue;
  }

  @Override
  public void produceResults(final Consumer<T> consumer, final ProducerContext context) {
    final ProducerListener producerListener = context.getListener();
    final String requestId = context.getId();
    final StatefulProducerRunnable<T> statefulRunnable = new StatefulProducerRunnable<T>(
        consumer,
        producerListener,
        PRODUCER_NAME,
        requestId) {
      @Override
      protected void onSuccess(T ignored) {
        producerListener.onProducerFinishWithSuccess(requestId, PRODUCER_NAME, null);
        mInputProducer.produceResults(consumer, context);
      }

      @Override
      protected void disposeResult(T ignored) {}

      @Override
      protected T getResult() throws Exception {
        return null;
      }
    };
    context.addCallbacks(
        new BaseProducerContextCallbacks() {
          @Override
          public void onCancellationRequested() {
            statefulRunnable.cancel();
            mThreadHandoffProducerQueue.remove(statefulRunnable);
          }
        });
    mThreadHandoffProducerQueue.addToQueueOrExecute(statefulRunnable);
  }
}

produceResults()進(jìn)行隊列任務(wù)

/**
 * Abstraction for computation.
 *
 * <p> Computation expressed as StatefulRunnable can be cancelled, but only if it has not
 * started yet.
 *
 * <p> For better decoupling of the code computing the result and the code that handles it, 4
 * separate methods are provided: getResult, onSuccess, onFailure and onCancellation.
 *
 * <p> This runnable can be run only once. Subsequent calls to run method won't have any effect.
 */
abstract public class StatefulRunnable<T> implements Runnable {

  @Override
  public final void run() {
    if (!mState.compareAndSet(STATE_CREATED, STATE_STARTED)) {
      return;
    }
    T result;
    try {
      result = getResult();
    } catch (Exception e) {
      mState.set(STATE_FAILED);
      onFailure(e);
      return;
    }

    mState.set(STATE_FINISHED);
    try {
      onSuccess(result);
    } finally {
      disposeResult(result);
    }
  }
}

完成回掉onSuccess,上面ThreadHandoffProducer:produceResults()&StatefulProducerRunnable:onSuccess():mInputProducer.produceResults(consumer, context);而這個mInputProducer是MultiplexProducer瘟滨,看下描述:

/**
 * Producer for combining multiple identical requests into a single request.
 *
 * <p>Requests using the same key will be combined into a single request. This request is only
 * cancelled when all underlying requests are cancelled, and returns values to all underlying
 * consumers. If the request has already return one or more results but has not finished, then
 * any requests with the same key will have the most recent result returned to them immediately.
 *  也就是說這個類候醒,把同樣key合并成一個request,并且這個request如果被取消杂瘸,那么下面所有的consumer將接收倒淫,
 *  還有就是如果這個request提前返回,但沒有完成胧沫,那么其它的request同樣key將會立即拿到返回的昌简。
 */
@ThreadSafe
public abstract class MultiplexProducer<K, T extends Closeable> implements Producer<T> {}

然后接著繼續(xù) mInputProducer.produceResults(forwardingConsumer,multiplexProducerContext); 當(dāng)前這個在MultiplexProducer的mInputProducer是BitmapMemoryCacheProducer,然后接收produceResults()進(jìn)行包裝

/**
 * Memory cache producer for the bitmap memory cache.
 */
public class BitmapMemoryCacheProducer implements Producer<CloseableReference<CloseableImage>> {

 public void produceResults(
      final Consumer<CloseableReference<CloseableImage>> consumer,
      final ProducerContext producerContext) {

    final ProducerListener listener = producerContext.getListener();
    final String requestId = producerContext.getId();
    listener.onProducerStart(requestId, getProducerName());
    final ImageRequest imageRequest = producerContext.getImageRequest();
    final Object callerContext = producerContext.getCallerContext();
    final CacheKey cacheKey = mCacheKeyFactory.getBitmapCacheKey(imageRequest, callerContext);

    CloseableReference<CloseableImage> cachedReference = mMemoryCache.get(cacheKey);

    if (cachedReference != null) {
      boolean isFinal = cachedReference.get().getQualityInfo().isOfFullQuality();
      if (isFinal) {
        listener.onProducerFinishWithSuccess(
            requestId,
            getProducerName(),
            listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "true") : null);
        consumer.onProgressUpdate(1f);
      }
      consumer.onNewResult(cachedReference, isFinal);
      cachedReference.close();
      if (isFinal) {
        return;
      }
    }

    if (producerContext.getLowestPermittedRequestLevel().getValue() >=
        ImageRequest.RequestLevel.BITMAP_MEMORY_CACHE.getValue()) {
      listener.onProducerFinishWithSuccess(
          requestId,
          getProducerName(),
          listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
      consumer.onNewResult(null, true);
      return;
    }

    Consumer<CloseableReference<CloseableImage>> wrappedConsumer = wrapConsumer(consumer, cacheKey);
    listener.onProducerFinishWithSuccess(
        requestId,
        getProducerName(),
        listener.requiresExtraMap(requestId) ? ImmutableMap.of(VALUE_FOUND, "false") : null);
    mInputProducer.produceResults(wrappedConsumer, producerContext);
  }
}

最后又走 mInputProducer.produceResults(wrappedConsumer, producerContext);這個不同了绒怨,變成了DecodeProducer去進(jìn)行圖片修飾纯赎,前面有說

/**
 * Decodes images.
 *
 * <p/> Progressive JPEGs are decoded progressively as new data arrives.
 */
public class DecodeProducer implements Producer<CloseableReference<CloseableImage>> {

 @Override
  public void produceResults(
      final Consumer<CloseableReference<CloseableImage>> consumer,
      final ProducerContext producerContext) {
    final ImageRequest imageRequest = producerContext.getImageRequest();
    ProgressiveDecoder progressiveDecoder;
    if (!UriUtil.isNetworkUri(imageRequest.getSourceUri())) {
      progressiveDecoder = new LocalImagesProgressiveDecoder(consumer, producerContext);
    } else {
      ProgressiveJpegParser jpegParser = new ProgressiveJpegParser(mByteArrayPool);
      progressiveDecoder = new NetworkImagesProgressiveDecoder(
          consumer,
          producerContext,
          jpegParser,
          mProgressiveJpegConfig);
    }
    mInputProducer.produceResults(progressiveDecoder, producerContext);
  }
}

mInputProducer這貨不看了,這個是ResizeAndRotateProducer南蹂,旋轉(zhuǎn)有關(guān)的犬金,NetworkImagesProgressiveDecoder里面有jobSclude

/**
 * Decodes images.
 *
 * <p/> Progressive JPEGs are decoded progressively as new data arrives.
 */
public class DecodeProducer implements Producer<CloseableReference<CloseableImage>> {

    public ProgressiveDecoder(
        final Consumer<CloseableReference<CloseableImage>> consumer,
        final ProducerContext producerContext) {
      super(consumer);
      mProducerContext = producerContext;
      mProducerListener = producerContext.getListener();
      mImageDecodeOptions = producerContext.getImageRequest().getImageDecodeOptions();
      mIsFinished = false;
      JobRunnable job = new JobRunnable() {
        @Override
        public void run(EncodedImage encodedImage, boolean isLast) {
          if (encodedImage != null) { // 這里開始接收到finsh
            if (mDownsampleEnabled) {
              ImageRequest request = producerContext.getImageRequest();
              if (mDownsampleEnabledForNetwork ||
                  !UriUtil.isNetworkUri(request.getSourceUri())) {
                encodedImage.setSampleSize(DownsampleUtil.determineSampleSize(
                    request, encodedImage));
              }
            }
            doDecode(encodedImage, isLast);
          }
        }
      };
      mJobScheduler = new JobScheduler(mExecutor, job, mImageDecodeOptions.minDecodeIntervalMs);
      mProducerContext.addCallbacks(
          new BaseProducerContextCallbacks() {
            @Override
            public void onIsIntermediateResultExpectedChanged() {
              if (mProducerContext.isIntermediateResultExpected()) {
                mJobScheduler.scheduleJob();
              }
            }
          });
    }
}

然后job做完,會拿到回掉六剥,走doDecode(encodedImage, isLast);

/**
 * Decodes images.
 *
 * <p/> Progressive JPEGs are decoded progressively as new data arrives.
 */
public class DecodeProducer implements Producer<CloseableReference<CloseableImage>> {

/** Performs the decode synchronously. */
    private void doDecode(EncodedImage encodedImage, boolean isLast) {
      if (isFinished() || !EncodedImage.isValid(encodedImage)) { // 校驗
        return;
      }

      try {
        long queueTime = mJobScheduler.getQueuedTime();// 校驗
        int length = isLast ?// 校驗
            encodedImage.getSize() : getIntermediateImageEndOffset(encodedImage);
        QualityInfo quality = isLast ? ImmutableQualityInfo.FULL_QUALITY : getQualityInfo();// 校驗

        // 這個還是ForwardingRequestListener晚顷,基本無用,因為里面包裝的requstListener是空
        mProducerListener.onProducerStart(mProducerContext.getId(), PRODUCER_NAME); 
        CloseableImage image = null;
        try {
          image = mImageDecoder.decodeImage(encodedImage, length, quality, mImageDecodeOptions); // 按圖片類型加載
        } catch (Exception e) {
          Map<String, String> extraMap = getExtraMap(image, queueTime, quality, isLast);
          mProducerListener.
              onProducerFinishWithFailure(mProducerContext.getId(), PRODUCER_NAME, e, extraMap);
          handleError(e);
          return;
        }
        Map<String, String> extraMap = getExtraMap(image, queueTime, quality, isLast);
        mProducerListener.
            onProducerFinishWithSuccess(mProducerContext.getId(), PRODUCER_NAME, extraMap);
        handleResult(image, isLast);
      } finally {
        EncodedImage.closeSafely(encodedImage);
      }
    }
}

mImageDecoder.decodeImage()將會調(diào)用ImageDecoder疗疟,這個類有點流弊该默,有誰知道'pinned'這個技術(shù)么,希望告訴我詳細(xì)策彤,關(guān)于內(nèi)存的栓袖,以前bitmap保存在Ashmen后來sdk變高以后,bitmap掛載在java heap去維護(hù)了

Fresco 的 Image Pipeline 負(fù)責(zé)圖片的獲取和管理店诗。

  • 圖片可以來自遠(yuǎn)程服務(wù)器裹刮,本地文件,或者Content Provider庞瘸,本地資源捧弃。壓縮后的文件緩存在本地存儲中,Bitmap數(shù)據(jù)緩存在內(nèi)存中擦囊。
  • 在5.0系統(tǒng)之后违霞,Image Pipeline 使用`pinned purgeables*將Bitmap數(shù)據(jù)存在native 內(nèi)存中。這要求圖片不使用時瞬场,要顯示地釋放內(nèi)存葛家。
  • SimpleDraweeView 自動處理了這個釋放過程,所以沒有特殊情況泌类,盡量使用SimpleDraweeView,在特殊的場合,如果有需要刃榨,也可以直接控制Image Pipeline弹砚。
Pinned purgeables behave as specified in {@link android.graphics.BitmapFactory.Options#inPurgeable}
public class BitmapFactory {

     public static class Options {
        /**
         * @deprecated As of {@link android.os.Build.VERSION_CODES#LOLLIPOP}, this is
         * ignored.
         *
         * In {@link android.os.Build.VERSION_CODES#KITKAT} and below, if this
         * is set to true, then the resulting bitmap will allocate its
         * pixels such that they can be purged if the system needs to reclaim
         * memory. In that instance, when the pixels need to be accessed again
         * (e.g. the bitmap is drawn, getPixels() is called), they will be
         * automatically re-decoded.
         *
         * <p>For the re-decode to happen, the bitmap must have access to the
         * encoded data, either by sharing a reference to the input
         * or by making a copy of it. This distinction is controlled by
         * inInputShareable. If this is true, then the bitmap may keep a shallow
         * reference to the input. If this is false, then the bitmap will
         * explicitly make a copy of the input data, and keep that. Even if
         * sharing is allowed, the implementation may still decide to make a
         * deep copy of the input data.</p>
         *
         * <p>While inPurgeable can help avoid big Dalvik heap allocations (from
         * API level 11 onward), it sacrifices performance predictability since any
         * image that the view system tries to draw may incur a decode delay which
         * can lead to dropped frames. Therefore, most apps should avoid using
         * inPurgeable to allow for a fast and fluid UI. To minimize Dalvik heap
         * allocations use the {@link #inBitmap} flag instead.</p>
         *
         * <p class="note"><strong>Note:</strong> This flag is ignored when used
         * with {@link #decodeResource(Resources, int,
         * android.graphics.BitmapFactory.Options)} or {@link #decodeFile(String,
         * android.graphics.BitmapFactory.Options)}.</p>
         */
        @Deprecated
        public boolean inPurgeable;
      }
}

基本是說,inPurgeable枢希,造成bitmap被系統(tǒng)回收通過pixels桌吃,因此,在fast和fluid ui(快速流暢)避免使用苞轿,GC時間長茅诱,為了使用小heap資源,sdk給inBitmap標(biāo)志代替

關(guān)于Bitmap的回收機(jī)制

系統(tǒng)的Bitmap內(nèi)存管理機(jī)制隨著Android系統(tǒng)的演進(jìn)可以分為三個階段搬卒,關(guān)于這部分可以參考官網(wǎng)文章Managing Bitmap Memory瑟俭。

  • 2.3.3及以下:Bitmap的像素數(shù)據(jù)存儲在native內(nèi)存中,但依舊會計算在一個進(jìn)程的內(nèi)存上限之中契邀。
  • 3.0~4.4:Bitmap的像素數(shù)據(jù)存儲在Java堆內(nèi)存中摆寄,解碼Bitmap時可以通過Options#inBitmap復(fù)用不再使用的Bitmap,從而減少系統(tǒng)gc坯门。但要求被復(fù)用的Bitmap和新Bitmap的像素數(shù)據(jù)一樣大微饥。
  • 5.0及以上:對于復(fù)用Bitmap的限制不再嚴(yán)格要求一樣大,只要別復(fù)用的Bitmap的像素數(shù)據(jù)不小于新Bitmap即可古戴。
/**
 * Decodes images.
 *
 * <p> ImageDecoder implements image type recognition and passes decode requests to
 * specialized methods implemented by subclasses.
 *
 * On dalvik, it produces 'pinned' purgeable bitmaps.
 *
 * <p> Pinned purgeables behave as specified in
 * {@link android.graphics.BitmapFactory.Options#inPurgeable} with one modification. The bitmap is
 * 'pinned' so is never purged.
 *
 * <p> For API 21 and higher, this class produces standard Bitmaps, as purgeability is not supported
 * on the most recent versions of Android.
 */
public class ImageDecoder {

/**
   * Decodes image.
   *
   * @param encodedImage input image (encoded bytes plus meta data)
   * @param length if image type supports decoding incomplete image then determines where
   *   the image data should be cut for decoding.
   * @param qualityInfo quality information for the image
   * @param options options that cange decode behavior
   */
  public CloseableImage decodeImage(
      final EncodedImage encodedImage,
      final int length,
      final QualityInfo qualityInfo,
      final ImageDecodeOptions options) {
    ImageFormat imageFormat = encodedImage.getImageFormat();
    if (imageFormat == null || imageFormat == ImageFormat.UNKNOWN) {
      imageFormat = ImageFormatChecker.getImageFormat_WrapIOException(
          encodedImage.getInputStream());
    }

    switch (imageFormat) {
      case UNKNOWN:
        throw new IllegalArgumentException("unknown image format");

      case JPEG:
        return decodeJpeg(encodedImage, length, qualityInfo);

      case GIF:
        return decodeGif(encodedImage, options);

      case WEBP_ANIMATED:
        return decodeAnimatedWebp(encodedImage, options);

      default:
        return decodeStaticImage(encodedImage);
    }
  }
}

最后這個bitmap的Cahe會傳到Multiplexer&ForwardingConsumer:consumer然后找到對應(yīng)訂閱Pair<Consumer<T>, ProducerContext> 然后就回到了最開始AbstractDraweeController:submitRequest()的datasource訂閱者了欠橘,完成成功,失敗现恼,數(shù)據(jù)持續(xù)更新一系列主線程刷新肃续。
好了,差不多介紹完主要的述暂,細(xì)節(jié)我會持續(xù)補(bǔ)充的痹升。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市畦韭,隨后出現(xiàn)的幾起案子疼蛾,更是在濱河造成了極大的恐慌,老刑警劉巖艺配,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件察郁,死亡現(xiàn)場離奇詭異,居然都是意外死亡转唉,警方通過查閱死者的電腦和手機(jī)皮钠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赠法,“玉大人麦轰,你說我怎么就攤上這事。” “怎么了款侵?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵末荐,是天一觀的道長。 經(jīng)常有香客問我新锈,道長甲脏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任妹笆,我火速辦了婚禮块请,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘拳缠。我一直安慰自己墩新,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布脊凰。 她就那樣靜靜地躺著抖棘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪狸涌。 梳的紋絲不亂的頭發(fā)上切省,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機(jī)與錄音帕胆,去河邊找鬼朝捆。 笑死,一個胖子當(dāng)著我的面吹牛懒豹,可吹牛的內(nèi)容都是我干的芙盘。 我是一名探鬼主播,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼脸秽,長吁一口氣:“原來是場噩夢啊……” “哼儒老!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起记餐,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤驮樊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后片酝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體囚衔,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年雕沿,在試婚紗的時候發(fā)現(xiàn)自己被綠了练湿。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡审轮,死狀恐怖肥哎,靈堂內(nèi)的尸體忽然破棺而出辽俗,到底是詐尸還是另有隱情,我是刑警寧澤贤姆,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布榆苞,位于F島的核電站,受9級特大地震影響霞捡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜薄疚,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一碧信、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧街夭,春花似錦砰碴、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至埃碱,卻和暖如春猖辫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砚殿。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工啃憎, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人似炎。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓辛萍,卻偏偏與公主長得像,于是被迫代替她去往敵國和親羡藐。 傳聞我的和親對象是個殘疾皇子贩毕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,129評論 25 707
  • 一、Bitmap 內(nèi)存回收 從3.0開始仆嗦,Bitmap 像素數(shù)據(jù)和 Bitmap 對象一起存放在 Dalvik 堆...
    秀花123閱讀 1,835評論 1 7
  • 店里的風(fēng)扇嗡嗡作響辉阶,也絲毫沒有減掉一絲悶熱,yougada欧啤,我點的中面好了睛藻,一勺花生粒、半勺碎蔥花邢隧,哈哈哈店印,...
    米花森閱讀 280評論 0 0
  • I 'm so tired.There are so many people around but they do...
    梅教主閱讀 422評論 2 0
  • 前言 一直覺得應(yīng)該把我的這個故事寫下來 之前寫過一大段保存在手機(jī)上 結(jié)果丟了 想起過去的事籠罩著白色的太陽 有些許...
    一點都不中二哦閱讀 227評論 0 0