Glide源碼分析之編解碼

今天整篇就圍繞一個數(shù)據(jù)后獲取階段,所謂后獲取指的是數(shù)據(jù)從網(wǎng)絡(luò)請求成功回本地后到轉(zhuǎn)換成所需的數(shù)據(jù)類型過程,總結(jié)出來就是兩個問題:

  • Glide的數(shù)據(jù)后獲取階段的流程?
  • Glide的編解碼階段流程?

1.數(shù)據(jù)后獲取階段流程

在<Glide緩存>里面提到過,網(wǎng)絡(luò)下載數(shù)據(jù)是在SourceGenerator中,下載成功后會把數(shù)據(jù)存在本地再從本地讀取,再回憶下這個過程。剛開始run1和run2dataToCache和sourceCacheGenerator為空,會走run3獲取數(shù)據(jù),成功請求后回調(diào)run4,給dataToCache賦值,因?yàn)闋顟B(tài)沒變,所以DecodeJob還是會調(diào)用SourceGenerator,現(xiàn)在會走run1,接著往后走。

// SourceGenerator.java
  @Override
  public boolean startNext() {
    // run 1
    if (dataToCache != null) {
      Object data = dataToCache;
      dataToCache = null;
      cacheData(data);
    }

    // run 2
    if (sourceCacheGenerator != null && sourceCacheGenerator.startNext()) {
      return true;
    }
    sourceCacheGenerator = null;

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      loadData = helper.getLoadData().get(loadDataListIndex++);
      if (loadData != null
          && (helper.getDiskCacheStrategy().isDataCacheable(loadData.fetcher.getDataSource())
          || helper.hasLoadPath(loadData.fetcher.getDataClass()))) {
        started = true;
        // run 3  
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

  @Override
  public void onDataReady(Object data) {
    DiskCacheStrategy diskCacheStrategy = helper.getDiskCacheStrategy();
    if (data != null && diskCacheStrategy.isDataCacheable(loadData.fetcher.getDataSource())) {
      dataToCache = data;
      // run 4
      cb.reschedule();
    } else {
      cb.onDataFetcherReady(loadData.sourceKey, data, loadData.fetcher,
          loadData.fetcher.getDataSource(), originalKey);
    }
  }

run1里面會調(diào)用cacheData, 會從DecodeHelper中獲取一個編碼器,把數(shù)據(jù)通過編碼器寫到本地文件中,文件緩存通過DiskCache管理,然后會給sourceCacheGenerator賦值,它其實(shí)是一個DataCacheGenerator類型,負(fù)責(zé)從本地加載數(shù)據(jù)。接著上面就走到run2, 從本地加載數(shù)據(jù)然后返回true.

  private void cacheData(Object dataToCache) {
    long startTime = LogTime.getLogTime();
    try {
      Encoder<Object> encoder = helper.getSourceEncoder(dataToCache);
      DataCacheWriter<Object> writer =
          new DataCacheWriter<>(encoder, dataToCache, helper.getOptions());
      originalKey = new DataCacheKey(loadData.sourceKey, helper.getSignature());
      helper.getDiskCache().put(originalKey, writer);
      if (Log.isLoggable(TAG, Log.VERBOSE)) {
        Log.v(TAG, "Finished encoding source to cache"
            + ", key: " + originalKey
            + ", data: " + dataToCache
            + ", encoder: " + encoder
            + ", duration: " + LogTime.getElapsedMillis(startTime));
      }
    } finally {
      loadData.fetcher.cleanup();
    }

    sourceCacheGenerator =
        new DataCacheGenerator(Collections.singletonList(loadData.sourceKey), helper, this);
  }

很明顯,接下來執(zhí)行到DataCacheGenerator中的startNext方法,在run1中根據(jù)File這種類型從注冊的ModelRegistry中取出對應(yīng)的ModelLoader,取出來的可能會有多個,然后循環(huán)遍歷這些ModelLoader,在run2中會構(gòu)造出DataFetcher,run3判斷拿到的DataFetcher轉(zhuǎn)換后的數(shù)據(jù)類型是否有對應(yīng)的Decoder,如果有就用這個DataFetcher加載從緩存拿到的cacheFile文件。

// DataCacheGenerator.java    
while (modelLoaders == null || !hasNextModelLoader()) {
      sourceIdIndex++;
      if (sourceIdIndex >= cacheKeys.size()) {
        return false;
      }

      Key sourceId = cacheKeys.get(sourceIdIndex);
      @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
      Key originalKey = new DataCacheKey(sourceId, helper.getSignature());
      cacheFile = helper.getDiskCache().get(originalKey);
      if (cacheFile != null) {
        this.sourceKey = sourceId;
        // run 1
        modelLoaders = helper.getModelLoaders(cacheFile);
        modelLoaderIndex = 0;
      }
    }

    loadData = null;
    boolean started = false;
    while (!started && hasNextModelLoader()) {
      ModelLoader<File, ?> modelLoader = modelLoaders.get(modelLoaderIndex++);
      // run 2
      loadData =
          modelLoader.buildLoadData(cacheFile, helper.getWidth(), helper.getHeight(),
              helper.getOptions());
      // run 3
      if (loadData != null && helper.hasLoadPath(loadData.fetcher.getDataClass())) {
        started = true;
        loadData.fetcher.loadData(helper.getPriority(), this);
      }
    }
    return started;
  }

看下對應(yīng)的File,會取到哪些ModelLoader,會取到有四個,分別是ByteBufferFileLoader,FileLoader,UnitModelLoader,其中兩個FileLoader分別對應(yīng)InputStream,FileDescriptor。

AfterDataFetcher.PNG

上面的循環(huán)會先取到第一個ByteBufferFileLoader,然后用ByteBufferFileFetcher去加載數(shù)據(jù),看下這個類,它是ByteBufferFileLoader的內(nèi)部類, 它的DataSourceDataSource.LOCAL,表示從數(shù)據(jù)來源是本地, 取到的數(shù)據(jù)類型是ByteBuffer.class, 在loadData中通過NIO內(nèi)存映射讀入文件。

// ByteBufferFileLoader.java
  private static final class ByteBufferFetcher implements DataFetcher<ByteBuffer> {

    private final File file;

    @Synthetic
    @SuppressWarnings("WeakerAccess")
    ByteBufferFetcher(File file) {
      this.file = file;
    }

    @Override
    public void loadData(@NonNull Priority priority,
        @NonNull DataCallback<? super ByteBuffer> callback) {
      ByteBuffer result;
      try {
        result = ByteBufferUtil.fromFile(file);
      } catch (IOException e) {
        if (Log.isLoggable(TAG, Log.DEBUG)) {
          Log.d(TAG, "Failed to obtain ByteBuffer for file", e);
        }
        callback.onLoadFailed(e);
        return;
      }

      callback.onDataReady(result);
    }
    ...

    @NonNull
    @Override
    public Class<ByteBuffer> getDataClass() {
      return ByteBuffer.class;
    }

    @NonNull
    @Override
    public DataSource getDataSource() {
      return DataSource.LOCAL;
    }
  }

文件成功映射后回調(diào)到DataCacheGenerator, 在這里是簡單的調(diào)用回調(diào)函數(shù),到這里數(shù)據(jù)來源變成了DataSource.DATA_DISK_CACHE,意思是已經(jīng)做了映射,但是未做修改的原始數(shù)據(jù)。這里的cb是在SourceGenerator中傳過來的。

// DataCacheGenerator.java  
@Override
  public void onDataReady(Object data) {
    cb.onDataFetcherReady(sourceKey, data, loadData.fetcher, DataSource.DATA_DISK_CACHE, sourceKey);
  }

SourceGenerator接口中只是簡單的再調(diào)用它上一級傳給它的cb,也就是DecodeJob, 到了這里就是賦值一個關(guān)鍵變量,data就是上面的ByteBufferFileFetcher取到的ByteBuffer數(shù)據(jù),然后會調(diào)用decodeFromRetrievedData進(jìn)行數(shù)據(jù)解碼。

// DecodeJob.java
  @Override
  public void onDataFetcherReady(Key sourceKey, Object data, DataFetcher<?> fetcher,
      DataSource dataSource, Key attemptedKey) {
    this.currentSourceKey = sourceKey;
    this.currentData = data;
    this.currentFetcher = fetcher;
    this.currentDataSource = dataSource;
    this.currentAttemptingKey = attemptedKey;
    if (Thread.currentThread() != currentThread) {
      runReason = RunReason.DECODE_DATA;
      callback.reschedule(this);
    } else {
      GlideTrace.beginSection("DecodeJob.decodeFromRetrievedData");
      try {
        decodeFromRetrievedData();
      } finally {
        GlideTrace.endSection();
      }
    }
  }

decodeFromRetrievedData中會一路調(diào)用,來到decodeFromFetcher, 會根據(jù)Data的類型ByteBufferDecodeHelper中獲取LoadPath,然后runLoadPath。

// DecodeJob.java  
private <Data> Resource<R> decodeFromFetcher(Data data, DataSource dataSource)
      throws GlideException {
    LoadPath<Data, ?, R> path = decodeHelper.getLoadPath((Class<Data>) data.getClass());
    return runLoadPath(data, dataSource, path);
}

private <Data, ResourceType> Resource<R> runLoadPath(Data data, DataSource dataSource,
      LoadPath<Data, ResourceType, R> path) throws GlideException {
    Options options = getOptionsWithHardwareConfig(dataSource);
    DataRewinder<Data> rewinder = glideContext.getRegistry().getRewinder(data);
    try {
      // ResourceType in DecodeCallback below is required for compilation to work with gradle.
      return path.load(
          rewinder, options, width, height, new DecodeCallback<ResourceType>(dataSource));
    } finally {
      rewinder.cleanup();
    }
}

后面經(jīng)過解碼和轉(zhuǎn)碼得到了數(shù)據(jù),會notifyEncodeAndRelease通知到上層,調(diào)用到notifyComplete回調(diào)到EngineJob:

// DecodeJob.java
  private void decodeFromRetrievedData() {
    ...
    Resource<R> resource = null;
    try {
      resource = decodeFromData(currentFetcher, currentData, currentDataSource);
    } catch (GlideException e) {
      e.setLoggingDetails(currentAttemptingKey, currentDataSource);
      throwables.add(e);
    }
    if (resource != null) {
      notifyEncodeAndRelease(resource, currentDataSource);
    } else {
      runGenerators();
    }
  }

  private void notifyEncodeAndRelease(Resource<R> resource, DataSource dataSource) {
    if (resource instanceof Initializable) {
      ((Initializable) resource).initialize();
    }
    ...
    notifyComplete(result, dataSource);
    ...
  }

  private void notifyComplete(Resource<R> resource, DataSource dataSource) {
    setNotifiedOrThrow();
    callback.onResourceReady(resource, dataSource);
  }

EngineJob中,會給主線程發(fā)送MSG_COMPLETE消息,回調(diào)到主線程執(zhí)行handleResultOnMainThread方法,在run 1中會回調(diào)onEngineJobComplete,其中l(wèi)istener是Engine。接著在run2中通知監(jiān)聽者Request,在Request里面調(diào)用TargetonResourceReady

// EngineJob.java
  @Override
  public void onResourceReady(Resource<R> resource, DataSource dataSource) {
    this.resource = resource;
    this.dataSource = dataSource;
    MAIN_THREAD_HANDLER.obtainMessage(MSG_COMPLETE, this).sendToTarget();
  }

    public boolean handleMessage(Message message) {
      EngineJob<?> job = (EngineJob<?>) message.obj;
      switch (message.what) {
        case MSG_COMPLETE:
          job.handleResultOnMainThread();
          break;
        ...
        default:
          throw new IllegalStateException("Unrecognized message: " + message.what);
      }
      return true;
    }

  void handleResultOnMainThread() {
    ...
    engineResource.acquire();
    // run 1
    listener.onEngineJobComplete(this, key, engineResource);

    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = cbs.size(); i < size; i++) {
      ResourceCallback cb = cbs.get(i);
      if (!isInIgnoredCallbacks(cb)) {
        engineResource.acquire();
        // run 2
        cb.onResourceReady(engineResource, dataSource);
      }
    }
    // Our request is complete, so we can release the resource.
    engineResource.release();

    release(false /*isRemovedFromQueue*/);
  }

上面調(diào)到的onEngineJobComplete是在Engine中,這里會先把資源放到active resources這一層內(nèi)存緩存中。注冊一個resourcelistener,在資源釋放的時候回調(diào),把資源從active resource中移除,挪到cache這一層的內(nèi)存緩存中:

// Engine
  public void onEngineJobComplete(EngineJob<?> engineJob, Key key, EngineResource<?> resource) {
    Util.assertMainThread();
    if (resource != null) {
      resource.setResourceListener(key, this);

      if (resource.isCacheable()) {
        activeResources.activate(key, resource);
      }
    }

    jobs.removeIfCurrent(key, engineJob);
  }

  public void onResourceReleased(Key cacheKey, EngineResource<?> resource) {
    Util.assertMainThread();
    activeResources.deactivate(cacheKey);
    if (resource.isCacheable()) {
      cache.put(cacheKey, resource);
    } else {
      resourceRecycler.recycle(resource);
    }
  }

2.LoadPath

所以看下LoadPath的源碼,它負(fù)責(zé)把獲取到的ByteBuffer放到一個個的DecodePath中進(jìn)行解碼轉(zhuǎn)換,有三個泛型,其中Data類型是獲取到的數(shù)據(jù)類型(比如ByteBuffer, InputStream), ResourceType是中間類型(可能有Gif/Bitmap),Transcode就是最后返回給應(yīng)用層的最終類型(可能有Drawable)等

// LoadPath.java
/**
 * For a given {@link com.bumptech.glide.load.data.DataFetcher} for a given data class, attempts to
 * fetch the data and then run it through one or more
 * {@link com.bumptech.glide.load.engine.DecodePath}s.
 *
 * @param <Data>         The type of data that will be fetched.
 * @param <ResourceType> The type of intermediate resource that will be decoded within one of the
 *                       {@link com.bumptech.glide.load.engine.DecodePath}s.
 * @param <Transcode>    The type of resource that will be returned as the result if the load and
 *                       one of the decode paths succeeds.
 */
public class LoadPath<Data, ResourceType, Transcode> {
  private final Class<Data> dataClass;
  private final Pool<List<Throwable>> listPool;
  private final List<? extends DecodePath<Data, ResourceType, Transcode>> decodePaths;
  private final String failureMessage;
  ...
}

知道了什么是LoadPath后再返回到前面的decodeFromFetcher中,看下LoadPath是怎么拿到的,先從緩存取如果沒有會從新構(gòu)造,構(gòu)造需要有一個參數(shù)DecodePath,會從decoderRegistry和transcoderRegistry分別獲取ResourceDecoder和ResourceTranscoder,分別用于解碼和轉(zhuǎn)碼。

// DecodeHelper.java
  <Data> LoadPath<Data, ?, Transcode> getLoadPath(Class<Data> dataClass) {
    return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);
  }
// Registry.java
  public <Data, TResource, Transcode> LoadPath<Data, TResource, Transcode> getLoadPath(
      @NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass,
      @NonNull Class<Transcode> transcodeClass) {
    LoadPath<Data, TResource, Transcode> result =
        loadPathCache.get(dataClass, resourceClass, transcodeClass);
    if (loadPathCache.isEmptyLoadPath(result)) {
      return null;
    } else if (result == null) {
      List<DecodePath<Data, TResource, Transcode>> decodePaths =
          getDecodePaths(dataClass, resourceClass, transcodeClass);
      if (decodePaths.isEmpty()) {
        result = null;
      } else {
        result =
            new LoadPath<>(
                dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool);
      }
      loadPathCache.put(dataClass, resourceClass, transcodeClass, result);
    }
    return result;
  }

  private <Data, TResource, Transcode> List<DecodePath<Data, TResource, Transcode>> getDecodePaths(
      @NonNull Class<Data> dataClass, @NonNull Class<TResource> resourceClass,
      @NonNull Class<Transcode> transcodeClass) {
    List<DecodePath<Data, TResource, Transcode>> decodePaths = new ArrayList<>();
    List<Class<TResource>> registeredResourceClasses =
        decoderRegistry.getResourceClasses(dataClass, resourceClass);

    for (Class<TResource> registeredResourceClass : registeredResourceClasses) {
      List<Class<Transcode>> registeredTranscodeClasses =
          transcoderRegistry.getTranscodeClasses(registeredResourceClass, transcodeClass);

      for (Class<Transcode> registeredTranscodeClass : registeredTranscodeClasses) {

        List<ResourceDecoder<Data, TResource>> decoders =
            decoderRegistry.getDecoders(dataClass, registeredResourceClass);
        ResourceTranscoder<TResource, Transcode> transcoder =
            transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);
        @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")
        DecodePath<Data, TResource, Transcode> path =
            new DecodePath<>(dataClass, registeredResourceClass, registeredTranscodeClass,
                decoders, transcoder, throwableListPool);
        decodePaths.add(path);
      }
    }
    return decodePaths;
  }

看下調(diào)試過程中有哪些具體的ResourceClasses和TranscodeClasses,可以看到ResourceClasses有三個

  • GifDrawable
  • Bitmap
  • BitmapDrawable

TranscodeClasses有一個Drawable,也就是最后返回給應(yīng)用層的會是Drawable.

decoder.PNG

構(gòu)造LoadPath需要一個很重要的參數(shù)DecodePath,接下來看看它。

3.DecodePath

再看看DecodePath的源碼, 三個泛型和前面的LoadPath是一樣的。解碼的時候回調(diào)用decode方法,這個方法完成下面三件事:

  • 調(diào)用decodeResource完成數(shù)據(jù)的解碼,得到decoded
  • 解碼完成后調(diào)用回調(diào)的onResourceDecoded,在回調(diào)里面回做一些比如圖片的變換,我們設(shè)置的transform就是在這里起作用
  • 對上面解碼得到的decoded進(jìn)行轉(zhuǎn)碼,返回轉(zhuǎn)碼成功的資源
public class DecodePath<DataType, ResourceType, Transcode> {
  private static final String TAG = "DecodePath";
  private final Class<DataType> dataClass;
  private final List<? extends ResourceDecoder<DataType, ResourceType>> decoders;
  private final ResourceTranscoder<ResourceType, Transcode> transcoder;
  private final Pool<List<Throwable>> listPool;
  private final String failureMessage;

  public DecodePath(Class<DataType> dataClass, Class<ResourceType> resourceClass,
      Class<Transcode> transcodeClass,
      List<? extends ResourceDecoder<DataType, ResourceType>> decoders,
      ResourceTranscoder<ResourceType, Transcode> transcoder, Pool<List<Throwable>> listPool) {
    this.dataClass = dataClass;
    this.decoders = decoders;
    this.transcoder = transcoder;
    this.listPool = listPool;
    failureMessage = "Failed DecodePath{" + dataClass.getSimpleName() + "->"
        + resourceClass.getSimpleName() + "->" + transcodeClass.getSimpleName() + "}";
  }

  public Resource<Transcode> decode(DataRewinder<DataType> rewinder, int width, int height,
      @NonNull Options options, DecodeCallback<ResourceType> callback) throws GlideException {
    Resource<ResourceType> decoded = decodeResource(rewinder, width, height, options);
    Resource<ResourceType> transformed = callback.onResourceDecoded(decoded);
    return transcoder.transcode(transformed, options);
  }

  @NonNull
  private Resource<ResourceType> decodeResource(DataRewinder<DataType> rewinder, int width,
      int height, @NonNull Options options) throws GlideException {
    List<Throwable> exceptions = Preconditions.checkNotNull(listPool.acquire());
    try {
      return decodeResourceWithList(rewinder, width, height, options, exceptions);
    } finally {
      listPool.release(exceptions);
    }
  }

  @NonNull
  private Resource<ResourceType> decodeResourceWithList(DataRewinder<DataType> rewinder, int width,
      int height, @NonNull Options options, List<Throwable> exceptions) throws GlideException {
    Resource<ResourceType> result = null;
    //noinspection ForLoopReplaceableByForEach to improve perf
    for (int i = 0, size = decoders.size(); i < size; i++) {
      ResourceDecoder<DataType, ResourceType> decoder = decoders.get(i);
      try {
        DataType data = rewinder.rewindAndGet();
        if (decoder.handles(data, options)) {
          data = rewinder.rewindAndGet();
          result = decoder.decode(data, width, height, options);
        }
      if (result != null) {
        break;
      }
    }
    return result;
  }
  ...

  interface DecodeCallback<ResourceType> {
    @NonNull
    Resource<ResourceType> onResourceDecoded(@NonNull Resource<ResourceType> resource);
  }
}

看一個具體的DecodePath的例子,從failureMessage中可以看到三個泛型分別是DirectByteBuffer->Bitmap->Drawable.同時資源也有設(shè)置寬高等屬性。

DecodePath.PNG

再返回到前面獲取LoadPath的過程中。

4.解碼

看下最終根據(jù)數(shù)據(jù)類型獲取到的DecodePath有三個:

  • dataClass: DirectByteBuffer, decoder: GifDecoder, transcoder: UnitTranscoder
  • dataClass: DirectByteBuffer, decoder: ByteBufferBitmapDecoder, transcoder: BitmapDrawableTranscoder
  • dataClass: DirectByteBuffer, decoder: BitmapDrawableDecoder, transcoder: UnitTranscoder
LoadPath.PNG

很明顯我們這里會是第二個起作用。看下ByteBufferBitmapDecoder中的源碼,通過Downsampler進(jìn)行對ByteBuffer進(jìn)行解碼成Bitmap,Downsampler里面根據(jù)采樣率、圖片大小等構(gòu)造一個Bitmap返回。

/**
 * Decodes {@link android.graphics.Bitmap Bitmaps} from {@link java.nio.ByteBuffer ByteBuffers}.
 */
public class ByteBufferBitmapDecoder implements ResourceDecoder<ByteBuffer, Bitmap> {
  private final Downsampler downsampler;

  public ByteBufferBitmapDecoder(Downsampler downsampler) {
    this.downsampler = downsampler;
  }

  @Override
  public boolean handles(@NonNull ByteBuffer source, @NonNull Options options) {
    return downsampler.handles(source);
  }

  @Override
  public Resource<Bitmap> decode(@NonNull ByteBuffer source, int width, int height,
      @NonNull Options options)
      throws IOException {
    InputStream is = ByteBufferUtil.toStream(source);
    return downsampler.decode(is, width, height, options);
  }
}

拿到Resource<Bitmap>后會通過BitmapDrawableTranscoder進(jìn)行轉(zhuǎn)碼,返回Resource<BitmapDrawable>

// BitmapDrawableTranscoder.java
/**
 * An {@link com.bumptech.glide.load.resource.transcode.ResourceTranscoder} that converts {@link
 * android.graphics.Bitmap}s into {@link android.graphics.drawable.BitmapDrawable}s.
 */
public class BitmapDrawableTranscoder implements ResourceTranscoder<Bitmap, BitmapDrawable> {
  private final Resources resources;

  // Public API.
  @SuppressWarnings("unused")
  public BitmapDrawableTranscoder(@NonNull Context context) {
    this(context.getResources());
  }

  /**
   * @deprecated Use {@link #BitmapDrawableTranscoder(Resources)}, {@code bitmapPool} is unused.
   */
  @Deprecated
  public BitmapDrawableTranscoder(
      @NonNull Resources resources, @SuppressWarnings("unused") BitmapPool bitmapPool) {
    this(resources);
  }

  public BitmapDrawableTranscoder(@NonNull Resources resources) {
    this.resources = Preconditions.checkNotNull(resources);
  }

  @Nullable
  @Override
  public Resource<BitmapDrawable> transcode(@NonNull Resource<Bitmap> toTranscode,
      @NonNull Options options) {
    return LazyBitmapDrawableResource.obtain(resources, toTranscode);
  }
}

最后是通過LazyBitmapDrawableResource.obtain返回的數(shù)據(jù), 這個可以實(shí)現(xiàn)懶加載,只有在真正調(diào)用get方法的時候才會分配BitmapDrawable:

// LazyBitmapDrawableResource.java
/**
 * Lazily allocates a {@link android.graphics.drawable.BitmapDrawable} from a given
 * {@link android.graphics.Bitmap} on the first call to {@link #get()}.
 */
public final class LazyBitmapDrawableResource implements Resource<BitmapDrawable>,
    Initializable {

  private final Resources resources;
  private final Resource<Bitmap> bitmapResource;

  ...

  @Nullable
  public static Resource<BitmapDrawable> obtain(
      @NonNull Resources resources, @Nullable Resource<Bitmap> bitmapResource) {
    if (bitmapResource == null) {
      return null;
    }
    return new LazyBitmapDrawableResource(resources, bitmapResource);

  }

  private LazyBitmapDrawableResource(@NonNull Resources resources,
      @NonNull Resource<Bitmap> bitmapResource) {
    this.resources = Preconditions.checkNotNull(resources);
    this.bitmapResource = Preconditions.checkNotNull(bitmapResource);
  }

  @NonNull
  @Override
  public Class<BitmapDrawable> getResourceClass() {
    return BitmapDrawable.class;
  }

  @NonNull
  @Override
  public BitmapDrawable get() {
    return new BitmapDrawable(resources, bitmapResource.get());
  }

  @Override
  public int getSize() {
    return bitmapResource.getSize();
  }

  @Override
  public void recycle() {
    bitmapResource.recycle();
  }

  @Override
  public void initialize() {
    if (bitmapResource instanceof Initializable) {
      ((Initializable) bitmapResource).initialize();
    }
  }
}

5.總結(jié)

Glide在數(shù)據(jù)請求成功后如果能允許緩存,就會緩存完成后通過讀取本地?cái)?shù)據(jù),然后完成解碼和轉(zhuǎn)碼返回給應(yīng)用層,也是基于門面模式,所以支持類型的轉(zhuǎn)接碼都會在Glide初始化的時候注冊到對應(yīng)的Registry中,數(shù)據(jù)下載成功后根據(jù)數(shù)據(jù)類型從Registry組裝LoadPath和DecodePath,完成解碼轉(zhuǎn)碼工作。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容