本文基于Glide 4.11.0

Glide加载过程有一个解码过程,比如将url加载为inputStream后,要将inputStream解码为Bitmap。

从Glide源码解析一我们大致知道了Glide加载的过程,所以我们可以直接从这里看起,在这个过程中我们以从文件中加载bitmap为例:

DecodeJob的一个方法:

private void decodeFromRetrievedData() {  if (Log.isLoggable(TAG, Log.VERBOSE)) {    logWithTimeAndKey("Retrieved data", startFetchTime,        "data: " + currentData            + ", cache key: " + currentSourceKey            + ", fetcher: " + currentFetcher);  }  Resource 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();  }}

主要是这个方法:resource =decodeFromData(currentFetcher, currentData, currentDataSource);

这时候currentData为FileInputStream,因为我们加载的是本地文件。

currentDateSource为LOCAL,即为本地的资源

我们继续找下去

resource = decodeFromData(currentFetcher, currentData, currentDataSource);

—————–>

Resource result = decodeFromFetcher(data, dataSource);

——————>

private  Resource decodeFromFetcher(Data data, DataSource dataSource)    throws GlideException {  LoadPath path = decodeHelper.getLoadPath((Class) data.getClass());  return runLoadPath(data, dataSource, path);

这里获取到LoadPath的对象,我么先看看LoadPath有什么?

我们可以看到一个DecodePaths:

DecodePath里面又保存着decoders

decoders便是我们需要的解码器,拿到解码器后就可以进行解码了。

那怎么拿到?

在Glide源码解析三中我们知道这些解码器都注册在Register中,所以我们也是要通过它来拿:

 LoadPath getLoadPath(Class dataClass) {  return glideContext.getRegistry().getLoadPath(dataClass, resourceClass, transcodeClass);}

—————->

@Nullablepublic  LoadPath getLoadPath(    @NonNull Class dataClass, @NonNull Class resourceClass,    @NonNull Class transcodeClass) {  LoadPath result =      loadPathCache.get(dataClass, resourceClass, transcodeClass);  if (loadPathCache.isEmptyLoadPath(result)) {    return null;  } else if (result == null) {    List<DecodePath> decodePaths =        getDecodePaths(dataClass, resourceClass, transcodeClass);    // It's possible there is no way to decode or transcode to the desired types from a given    // data class.    if (decodePaths.isEmpty()) {      result = null;    } else {      result =          new LoadPath(              dataClass, resourceClass, transcodeClass, decodePaths, throwableListPool);    }    loadPathCache.put(dataClass, resourceClass, transcodeClass, result);  }  return result;}

首先会先从缓存中拿,缓存中拿不到再通过下面的方法去拿:

List<DecodePath> decodePaths =getDecodePaths(dataClass, resourceClass, transcodeClass);

private  List<DecodePath> getDecodePaths(    @NonNull Class dataClass, @NonNull Class resourceClass,    @NonNull Class transcodeClass) {  List<DecodePath> decodePaths = new ArrayList();  List<Class> registeredResourceClasses =      decoderRegistry.getResourceClasses(dataClass, resourceClass);  for (Class registeredResourceClass : registeredResourceClasses) {    List<Class> registeredTranscodeClasses =        transcoderRegistry.getTranscodeClasses(registeredResourceClass, transcodeClass);    for (Class registeredTranscodeClass : registeredTranscodeClasses) {      List<ResourceDecoder> decoders =          decoderRegistry.getDecoders(dataClass, registeredResourceClass);      ResourceTranscoder transcoder =          transcoderRegistry.get(registeredResourceClass, registeredTranscodeClass);      @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops")      DecodePath path =          new DecodePath(dataClass, registeredResourceClass, registeredTranscodeClass,              decoders, transcoder, throwableListPool);      decodePaths.add(path);    }  }  return decodePaths;}

该方法各个参数如下:

dataClass为InputStream,这是被解码的对象

resourceClass为Object,要解码成为Object

transcodeClass为Drawable,要转码为Drawable

我们看这个方法:

decoderRegistry.getResourceClasses:

public synchronized  List<Class> getResourceClasses(@NonNull Class dataClass,    @NonNull Class resourceClass) {  List<Class> result = new ArrayList();  for (String bucket : bucketPriorityList) {    List<Entry> entries = decoders.get(bucket);    if (entries == null) {      continue;    }    for (Entry entry : entries) {      if (entry.handles(dataClass, resourceClass)          && !result.contains((Class) entry.resourceClass)) {        result.add((Class) entry.resourceClass);      }    }  }  return result;}

该方法是为了获取解码器中的resourceClass,即解码后的资源类型。

我们可以看到decoder这个map里面的内容:

各种类型对应的解码器。

只有满足entry.handles(dataClass, resourceClass),才能被添加返回:

public boolean handles(@NonNull Class dataClass, @NonNull Class resourceClass) {  return this.dataClass.isAssignableFrom(dataClass) && resourceClass      .isAssignableFrom(this.resourceClass);}

由于我们的resourceClass是Object,因此resourceClass .isAssignableFrom(this.resourceClass)总是成立的,所以就看:this.dataClass.isAssignableFrom(dataClass)

而我们的dataClass是InputStream,打开各种类型,可以看到哪些的dataClass是InputStream:

上面框错了,应该框resourceClass,另外FrameSequenceDrawable是我自定义后注册进去的,所以Glide原生的是没有的。

所以最终返回的resource为:

接下来是针对每一种resourceClass获取对应的转码类(要转成的对象):

public synchronized  List<Class> getTranscodeClasses(    @NonNull Class resourceClass, @NonNull Class transcodeClass) {  List<Class> transcodeClasses = new ArrayList();  // GifDrawable -> Drawable is just the UnitTranscoder, as is GifDrawable -> GifDrawable.  if (transcodeClass.isAssignableFrom(resourceClass)) {    transcodeClasses.add(transcodeClass);    return transcodeClasses;  }  for (Entry entry : transcoders) {    if (entry.handles(resourceClass, transcodeClass)) {      transcodeClasses.add(transcodeClass);    }  }  return transcodeClasses;}

如果transcodeClass是resourceClass的父类那就直接返回。

第一个GifDrawable,返回的registeredTranscodeClasses为:

然后根据dataClass, registeredResourceClass获取decoders:

然后根据registeredResourceClass和registeredTranscodeClass获取transcoder

上面具体的获取过程是类似的,就不过多分析了。

然后构造DecodePath,放进下面的集合里面:

List<DecodePath> decodePaths = new ArrayList();

循环获取之后,最终得到的decodePaths如下:

大致流程:

1、先根据传进来的resourceClass获取注册表中所有注册的resourceClass得到List<Class> registeredResourceClasses

2、两层for循环:

(1)外层:根据registeredResourceClasses获取转码的class :List<Class> registeredTranscodeClasses

(2)内层:

a、根据资源resourceClass获取所有的解码器。

b、根据资源resourceClass和转码transcodeClass获取所有的转码器。

c、构造DecodePath,放进集合里面。

最后得到的List<DecodePath> decodePaths被放到LoadPath对象里面(上一层方法可看到)

我们又回到DecodeJob中的方法:

private  Resource decodeFromFetcher(Data data, DataSource dataSource)    throws GlideException {  LoadPath path = decodeHelper.getLoadPath((Class) data.getClass());  return runLoadPath(data, dataSource, path);}

获取到LoadPath后接下来就是要开始执行了runLoadPath了。

找下去可以看到该方法:

return path.load(          rewinder, options, width, height, new DecodeCallback(dataSource));

该方法属于LoadPath对象。

层层追溯后,最终来到下面的方法:

private Resource loadWithExceptionList(DataRewinder rewinder,    @NonNull Options options,    int width, int height, DecodePath.DecodeCallback decodeCallback,    List exceptions) throws GlideException {  Resource result = null;  //noinspection ForLoopReplaceableByForEach to improve perf  for (int i = 0, size = decodePaths.size(); i < size; i++) {    DecodePath path = decodePaths.get(i);    try {      result = path.decode(rewinder, width, height, options, decodeCallback);    } catch (GlideException e) {      exceptions.add(e);    }    if (result != null) {      break;    }  }  if (result == null) {    throw new GlideException(failureMessage, new ArrayList(exceptions));  }  return result;}

该方法在LoadPath里面,遍历decodePaths(这是我们之前获取后放在LoadPath中的)进行解码:

result = path.decode(rewinder, width, height, options, decodeCallback);

然后来到:

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

我们这里需要看的就是:decodeResource:

最终来到DecodePath里面的方法:

@NonNullprivate Resource decodeResourceWithList(DataRewinder rewinder, int width,    int height, @NonNull Options options, List exceptions) throws GlideException {  Resource result = null;  //noinspection ForLoopReplaceableByForEach to improve perf  for (int i = 0, size = decoders.size(); i < size; i++) {    ResourceDecoder decoder = decoders.get(i);    try {      DataType data = rewinder.rewindAndGet();      if (decoder.handles(data, options)) {        data = rewinder.rewindAndGet();        result = decoder.decode(data, width, height, options);      }      // Some decoders throw unexpectedly. If they do, we shouldn't fail the entire load path, but      // instead log and continue. See #2406 for an example.    } catch (IOException | RuntimeException | OutOfMemoryError e) {      if (Log.isLoggable(TAG, Log.VERBOSE)) {        Log.v(TAG, "Failed to decode data for " + decoder, e);      }      exceptions.add(e);    }    if (result != null) {      break;    }  }  if (result == null) {    throw new GlideException(failureMessage, new ArrayList(exceptions));  }  return result;}

这个方法:decoder.handles(data, options)是判断该解码器是否可以对该资源进行解码,这个方法写在每个解码器里面。

DataRewinder里面放着需要进行解码的数据。

解码后将资源返回。

又回到这个方法:

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

这一句Resource transformed = callback.onResourceDecoded(decoded);

是对资源进行变换处理,比如图片的缩放,剪裁等等,这个功能单独拎出来讲。

接下来便是运用转码器进行资源的转码:

transcoder.transcode(transformed, options)

到此就结束了。

转载请标明:https://www.cnblogs.com/tangZH/p/12912698.html