本文基于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 = decod服务器托管网eFromFetcher(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); }
—————->
@Nullable public 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> 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> decodePaths =getDecodePaths(dataClass, resourceClass, transcodeClass);
private List> getDecodePaths( @NonNull Class dataClass, @NonNull Class resourceClass, @NonNull Class transcodeClass) { List> decodePaths = new ArrayList(); List> registeredResourceClasses = decoderRegistry.getResourceClasses(dataClass, resourceClass); for (Class registeredResourceClass : registeredResourceClasses) { List> registeredTranscodeClasses = transcoderRegistry.getTranscodeClasses(registeredResourceClass, transcodeClass); for (Class registeredTranscodeClass : registeredTranscodeClasses) { List> 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> getResourceClasses(@NonNull Class dataClass, @NonNull Class resourceClass) { List> result = new ArrayList(); for (String bucket : bucketPriorityList) { List> 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> getTranscodeClasses( @NonNull Class resourceClass, @NonNull Class transcodeClass) { List> transcodeClasses = new ArrayList(); // GifDrawable -> Drawable is just the UnitTranscoder, as is GifDrawable -> GifDrawabl服务器托管网e. 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> decodePaths = new ArrayList();
循环获取之后,最终得到的decodePaths如下:
大致流程:
1、先根据传进来的resourceClass获取注册表中所有注册的resourceClass得到List> registeredResourceClasses
2、两层for循环:
(1)外层:根据registeredResourceClasses获取转码的class :List> registeredTranscodeClasses
(2)内层:
a、根据资源resourceClass获取所有的解码器。
b、根据资源resourceClass和转码transcodeClass获取所有的转码器。
c、构造DecodePath,放进集合里面。
最后得到的List> 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 ) { 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里面的方法:
@NonNull private 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 ) { 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
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net
机房租用,北京机房租用,IDC机房托管, http://www.fwqtg.net
相关推荐: 新火种AI|从GPT-5到AI芯片厂,山姆·奥特曼在下一盘多大的棋?
作者:文子 编辑:小迪 这一次OpenAI的野心真的太大了。 大规模招商,打造全球AI芯片厂 随着OpenAI估值逼近1000亿大关,山姆奥特曼的野心再也藏不住了。他不再满足于血拼谷歌和苹果,而是直接向算力霸主英伟达开战。 据知情人士透露,山姆奥特曼正在积极向…