Glide 源码解析

来源:互联网 发布:unity3d 热力图 编辑:程序博客网 时间:2024/04/29 09:05

泰国举行的谷歌开发者论坛上,谷歌为我们介绍了一个名叫 Glide 的图片加载库,作者是bumptech。这个库被广泛的运用在google的开源项目中,包括2014年google I/O大会上发布的官方app。Glide和Picasso使用上有90%的相似度,但是内部实现机制有很大区别 Glide介绍。

1.主要特点

(1)支持Memory和Disk图片缓存。
(2)支持gif和webp格式图片。
(3)根据Activity/Fragment生命周期自动管理请求。
(4)使用Bitmap Pool可以使Bitmap复用。
(5)对于回收的Bitmap会主动调用recycle,减小系统回收压力。

2. 总体设计

总体设计图

基本概念

RequestManager:请求管理,每一个Activity都会创建一个RequestManager,根据对应Activity的生命周期管理该Activity上所以的图片请求。

Engine:加载图片的引擎,根据Request创建EngineJob和DecodeJob。

EngineJob:图片加载。

DecodeJob:图片处理。

流程图

这里是大概的总体流程图, 具体的细节中流程下面继续分析。
总体流程图

3. 核心类介绍

3.1 Gilde 
用于保存整个框架中的配置。

重要方法:

  1. public static RequestManager with(FragmentActivity activity) {
  2. RequestManagerRetriever retriever = RequestManagerRetriever.get();
  3. return retriever.get(activity);
  4. }

用于创建RequestManager,这里是Glide通过Activity/Fragment生命周期管理Request原理所在,这个类很关键、很关键、很关键,重要的事情我只说三遍。
主要原理是创建一个自定义Fragment,然后通过自定义Fragment生命周期操作RequestManager,从而达到管理Request。

RequestManager创建流程图

3.2 RequestManagerRetriever

  1. RequestManager supportFragmentGet(Context context, FragmentManager fm) {
  2. SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);
  3. RequestManager requestManager = current.getRequestManager();
  4. if (requestManager == null) {
  5. requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());
  6. current.setRequestManager(requestManager);
  7. }
  8. return requestManager;
  9. }

这里判断是否只当前RequestManagerFragment是否存在RequestManager,保证一个Activity对应一个RequestManager, 这样有利于管理一个Activity上所有的Request。创建RequestManager的时候会将RequestManagerFragment中的回调接口赋值给RequestManager,达到RequestManager监听RequestManagerFragment的生命周期。

3.3 RequestManager
成员变量:
(1)Lifecycle lifecycle,用于监听RequestManagerFragment生命周期。
(2)RequestTracker requestTracker, 用于保存当前RequestManager所有的请求和带处理的请求。

重要方法:

  1. @Override
  2. //开始暂停的请求
  3. public void onStart() {
  4. resumeRequests();
  5. }
  6. //停止所有的请求
  7. @Override
  8. public void onStop() {
  9. pauseRequests();
  10. }
  11.  
  12. //关闭所以的请求
  13. @Override
  14. public void onDestroy() {
  15. requestTracker.clearRequests();
  16. }
  17.  
  18. //创建RequestBuild
  19. public DrawableTypeRequest<String> load(String string) {
  20. return (DrawableTypeRequest<String>) fromString().load(string);
  21. }
  22.  
  23. public <Y extends Target<TranscodeType>> Y into(Y target) {
  24. ...
  25. Request previous = target.getRequest();
  26. //停止当前target中的Request。
  27. if (previous != null) {
  28. previous.clear(); //这个地方很关键,见Request解析
  29. requestTracker.removeRequest(previous);
  30. previous.recycle();
  31. }
  32. ...
  33. return target;
  34. }

3.4 DrawableRequestBuilder 
用于创建Request。 这里面包括很多方法,主要是配置加载图片的url、大小、动画、ImageView对象、自定义图片处理接口等。

3.5 Request 
主要是操作请求,方法都很简单。

  1. @Override
  2. public void clear() {
  3. ...
  4. if (resource != null) {
  5. //这里会释放资源
  6. releaseResource(resource);
  7. }
  8. ...
  9. }

这里的基本原理是当有Target使用Resource(Resource见下文)时,Resource中的引用记数值会加一,当释放资源Resource中的引用记数值减一。当没有Target使用的时候就会释放资源,放进Lrucache中。

3.7 EngineResource
实现Resource接口,使用装饰模式,里面包含实际的Resource对象

  1. void release() {
  2. if (--acquired == 0) {
  3. listener.onResourceReleased(key, this);
  4. }
  5. }
  6.  
  7. void acquire() {
  8. ++acquired;
  9. }
  10.  
  11. @Override
  12. public void recycle() {
  13. isRecycled = true;
  14. resource.recycle();
  15. }

acquire和release两个方法是对资源引用计数;recycle释放资源,一般在Lrucache饱和时会触发。

3.8 Engine(重要) 
请求引擎,主要做请求的开始的初始化。

3.8.1 load方法
这个方法很长,将分为几步分析

(1)获取MemoryCache中缓存 首先创建当前Request的缓存key,通过key值从MemoryCache中获取缓存,判断缓存是否存在。

  1. private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {
  2. ....
  3. EngineResource<?> cached = getEngineResourceFromCache(key);
  4. if (cached != null) {
  5. cached.acquire();
  6. activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));
  7. }
  8. return cached;
  9. }
  10.  
  11. @SuppressWarnings("unchecked")
  12. private EngineResource<?> getEngineResourceFromCache(Key key) {
  13. Resource<?> cached = cache.remove(key);
  14.  
  15. final EngineResource result;
  16. ...
  17. return result;
  18. }

(重点)从缓存中获取的时候使用的cache.remove(key),然后将值保存在activeResources中,然后将Resource的引用计数加一。
优点:
> 正使用的Resource将会在activeResources中,不会出现在cache中,当MemoryCache中缓存饱和的时候或者系统内存不足的时候,清理Bitmap可以直接调用recycle,不用考虑Bitmap正在使用导致异常,加快系统的回收。


(2)获取activeResources中缓存
activeResources通过弱引用保存recouse ,也是通过key获取缓存,

  1. private EngineResource<?> loadFromActiveResources(Key key, boolean isMemoryCacheable)

(3)判断当前的请求任务是否已经存在

  1. EngineJob current = jobs.get(key);
  2. if (current != null) {
  3. current.addCallback(cb);
  4. return new LoadStatus(cb, current);
  5. }

如果任务请求已经存在,直接将回调事件传递给已经存在的EngineJob,用于请求成功后触发回调。


(4)执行请求任务

  1. EngineJob engineJob = engineJobFactory.build(key, isMemoryCacheable);
  2. DecodeJob<T, Z, R> decodeJob = new DecodeJob<T, Z, R>(key, width, height, fetcher, loadProvider, transformation,
  3. transcoder, diskCacheProvider, diskCacheStrategy, priority);
  4. EngineRunnable runnable = new EngineRunnable(engineJob, decodeJob, priority);
  5. jobs.put(key, engineJob);
  6. engineJob.addCallback(cb);
  7. engineJob.start(runnable);

3.9 EngineRunnable
请求执行Runnable,主要功能请求资源、处理资源、缓存资源。

  1. private Resource<?> decodeFromCache() throws Exception {
  2. Resource<?> result = null;
  3. try {
  4. result = decodeJob.decodeResultFromCache();
  5. } catch (Exception e) {
  6. if (Log.isLoggable(TAG, Log.DEBUG)) {
  7. Log.d(TAG, "Exception decoding result from cache: " + e);
  8. }
  9. }
  10.  
  11. if (result == null) {
  12. result = decodeJob.decodeSourceFromCache();
  13. }
  14. return result;
  15. }
  16.  
  17. private Resource<?> decodeFromSource() throws Exception {
  18. return decodeJob.decodeFromSource();
  19. }

加载DiskCache和网络资源。加载DiskCache包括两个,因为Glide默认是保存处理后的资源(压缩和裁剪后),缓存方式可以自定义配置。如果客户端规范设计,ImageView大小大部分相同可以节省图片加载时间和Disk资源。

3.10 DecodeJob

  1. public Resource<Z> decodeResultFromCache() throws Exception
  2. public Resource<Z> decodeSourceFromCache() throws Exception

从缓存中获取处理后的资源。上面有关Key的内容,Key是一个对象,可以获取key和orginKey。decodeResultFromCache就是通过key获取缓存,decodeSourceFromCache()就是通过orginKey获取缓存。

  1. private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded)

处理和包装资源;缓存资源。

  1. //保存原资源
  2. private Resource<T> cacheAndDecodeSourceData(A data) throws IOException
  3. //保存处理后的资源
  4. private void writeTransformedToCache(Resource<T> transformed)

3.11 Transformation

  1. Resource<T> transform(Resource<T> resource, int outWidth, int outHeight);

处理资源,这里面出现BitmapPool类,达到Bitmap复用。

3.12 ResourceDecoder 
用于将文件、IO流转化为Resource

3.13BitmapPool 
用于存放从LruCache中remove的Bitmap, 用于后面创建Bitmap时候的重复利用。

3.杂谈

Glide的架构扩展性高,但是难以理解,各种接口、泛型,需要一定的学习才能熟练运用。

Glide的优点:

(1)支持对处理后的资源Disk缓存。
(2)通过BitmapPool对Bitmap复用。
(3)使用activityResources缓存正在使用的resource,对于BitmapPool饱和移除的Bitmap直接调用recycle加速内存回收。

0 0