转载:http://m.aspku.com/view-141093.html

这篇文章主要介绍了从源码分析Android的Glide库的图片加载流程及特点,Glide库是Android下一款人气很高的多媒体资源管理库,特别是在处理gif加载方面受到众多开发者青睐,需要的朋友可以参考下

0.基础知识
Glide中有一部分单词,我不知道用什么中文可以确切的表达出含义,用英文单词可能在行文中更加合适,还有一些词在Glide中有特别的含义,我理解的可能也不深入,这里先记录一下。

(1)View: 一般情况下,指Android中的View及其子类控件(包括自定义的),尤其指ImageView。这些控件可在上面绘制Drawable
(2)Target: Glide中重要的概念,目标。它即可以指封装了一个View的Target(ViewTarget),也可以不包含View(SimpleTarget)。
(3)Drawable: 指Android中的Drawable类或者它的子类,如BitmapDrawable等。或者Glide中基础Drawable实现的自定义Drawable(如GifDrawable等)
(4)Request - 加载请求,可以是网络请求或者其他任何下载图片的请求,也是Glide中的一个类。
(5)Model:数据源的提供者,如Url,文件路径等,可以从model中获取InputStream。
(6)Signature:签名,可以唯一地标识一个对象。
(7)recycle():Glide中Resource类有此方法,表示该资源不被引用,可以放入池中(此时并没有释放空间)。Android中Bitmap也有此方法,表示释放Bitmap占用的内存。

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 
用于保存整个框架中的配置。
重要方法:

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

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

3.2 RequestManagerRetriever

RequestManager supportFragmentGet(Context context, FragmentManager fm) {SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm);RequestManager requestManager = current.getRequestManager();if (requestManager == null) {requestManager = new RequestManager(context, current.getLifecycle(), current.getRequestManagerTreeNode());current.setRequestManager(requestManager);}return requestManager;
}

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

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

@Override
//开始暂停的请求
public void onStart() {resumeRequests();
}
//停止所有的请求
@Override
public void onStop() {pauseRequests();
}//关闭所以的请求
@Override
public void onDestroy() {requestTracker.clearRequests();
}//创建RequestBuild
public DrawableTypeRequest<String> load(String string) {return (DrawableTypeRequest<String>) fromString().load(string);
}public <Y extends Target<TranscodeType>> Y into(Y target) {...Request previous = target.getRequest();//停止当前target中的Request。if (previous != null) {previous.clear(); //这个地方很关键,见Request解析requestTracker.removeRequest(previous);previous.recycle();}...return target;
}

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

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

@Override
public void clear() {...if (resource != null) {//这里会释放资源releaseResource(resource);}...
}

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

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

void release() {if (--acquired == 0) {listener.onResourceReleased(key, this);}
} void acquire() {++acquired;
} @Override
public void recycle() {isRecycled = true;resource.recycle();
}

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

3.7 Engine(重要) 
请求引擎,主要做请求的开始的初始化。
3.7.1 load方法
这个方法很长,将分为几步分析
(1)获取MemoryCache中缓存 首先创建当前Request的缓存key,通过key值从MemoryCache中获取缓存,判断缓存是否存在。

private EngineResource<?> loadFromCache(Key key, boolean isMemoryCacheable) {....EngineResource<?> cached = getEngineResourceFromCache(key);if (cached != null) {cached.acquire();activeResources.put(key, new ResourceWeakReference(key, cached, getReferenceQueue()));}return cached;
}@SuppressWarnings("unchecked")
private EngineResource<?> getEngineResourceFromCache(Key key) {Resource<?> cached = cache.remove(key);final EngineResource result;...return result;
}

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

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

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

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

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

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

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

private Resource<?> decodeFromCache() throws Exception {Resource<?> result = null;try {result = decodeJob.decodeResultFromCache();} catch (Exception e) {if (Log.isLoggable(TAG, Log.DEBUG)) {Log.d(TAG, "Exception decoding result from cache: " + e);}}if (result == null) {result = decodeJob.decodeSourceFromCache();}return result;
} private Resource<?> decodeFromSource() throws Exception {return decodeJob.decodeFromSource();
}

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

3.9 DecodeJob
public Resource<Z> decodeResultFromCache() throws Exception  
从缓存中获取处理后的资源。上面有关Key的内容,Key是一个对象,可以获取key和orginKey。decodeResultFromCache就是通过key获取缓存,decodeSourceFromCache()就是通过orginKey获取缓存。
private Resource<Z> transformEncodeAndTranscode(Resource<T> decoded)

处理和包装资源;缓存资源。
保存原资源
private Resource<T> cacheAndDecodeSourceData(A data) throws IOException  
保存处理后的资源
private void writeTransformedToCache(Resource<T> transformed)

3.10 Transformation
Resource<T> transform(Resource<T> resource, int outWidth, int outHeight);
处理资源,这里面出现BitmapPool类,达到Bitmap复用。
3.11 ResourceDecoder 
用于将文件、IO流转化为Resource
3.12 BitmapPool 
用于存放从LruCache中remove的Bitmap, 用于后面创建Bitmap时候的重复利用。

4.杂谈
Glide的架构扩展性高,但是难以理解,各种接口、泛型,需要一定的学习才能熟练运用。
Glide的优点:
(1)支持对处理后的资源Disk缓存。
(2)通过BitmapPool对Bitmap复用。
(3)使用activityResources缓存正在使用的resource,对于BitmapPool饱和移除的Bitmap直接调用recycle加速内存回收。

从源码分析Android的Glide库的图片加载流程及特点相关推荐

  1. Spring源码分析(1) —— 从Xml的加载到解析

    题外话: 接口&多态 我有一辆自行车,每天骑着它去上班 package com.zhao.SpringIoc;public class Bike {public void go() {Syst ...

  2. skynet源码分析(11)--skynet的配置加载

    作者:shihuaping0918@163.com,转载请注明作者 skynet中的源码已经分析得差不多了,还有启动过程没有分析.skynet的配置文件是以lua格式来写的.使用过skynet的都清楚 ...

  3. Glide 4.9源码解析-图片加载流程

    本文Glide源码基于4.9,版本下载地址如下:Glide 4.9 前言 由于Glide源码真的很复杂,因此本文只分析和贴出与图片加载流程相关的功能以及代码.另外本文Glide源码基于4.9,与3.x ...

  4. 源码分析Android Handler是如何实现线程间通信的

    源码分析Android Handler是如何实现线程间通信的 Handler作为Android消息通信的基础,它的使用是每一个开发者都必须掌握的.开发者从一开始就被告知必须在主线程中进行UI操作.但H ...

  5. Spring源码之ResourceLoader(二):PathMatchingResourcePatternResolver实现getResources加载多文件

    Spring源码之ResourceLoader二:PathMatchingResourcePatternResolver实现getResources加载多文件 findAllClassPathReso ...

  6. PTMs:QLoRA技巧之源码解读(qlora.py文件)—解析命令与加载参数→数据预处理→模型训练+评估+推理

    PTMs:QLoRA技巧之源码解读(qlora.py文件)-解析命令与加载参数→数据预处理→模型训练+评估+推理 目录 QLoRA技巧之源码解读(qlora.py文件)-解析命令与加载参数→数据预处理 ...

  7. 短视频直播源码,显示和隐藏 类似淘宝加载

    短视频直播源码,显示和隐藏 类似淘宝加载的相关代码 1:当点击HomeActity中的Tab时,首先 case 1:case 2:if ( fg2== null) {fg2 = new Fragmen ...

  8. Glide图片加载流程浅析

    Glide是Android开发中常用的图片框架,其最基本用法例如Glide.with(context).load(url).into(imageView),我们沿着此链式调用的顺序一窥Glide图片加 ...

  9. Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析-[Android取经之路]

    摘要:本节主要来讲解Android10.0 logd.logcat读写日志源码内容 阅读本文大约需要花费20分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Andro ...

最新文章

  1. leetcode -eleven:Container With Most Water
  2. 防止过拟合以及解决过拟合
  3. 【渝粤题库】陕西师范大学200411 数学建模 作业(专升本)
  4. python self 序列_python中序列化对象
  5. python登录系统的实现方法_python实现简单登陆系统
  6. dj鲜生-23-模板抽离-继承的小结
  7. 关于MFC里面位图相关的操作
  8. 深圳行:1207-Day 1 - 到达
  9. JS表单学习笔记(思维导图)
  10. jenkins 基础配置安装(Ⅰ)
  11. Mac切换英文大写,不能锁定,该如何解决
  12. 华为热设计工程师待遇_【华为热设计工程师面试】华为热设计工程师大家要慎重考虑。-看准网...
  13. 武汉都有哪些互联网公司?
  14. css中的@media用法总结
  15. ps——霓虹灯字体效果
  16. 05月11日三支有望飙涨股与操盘策略分析
  17. java date类型大小比较_java中date类型如何比较大小
  18. 软件企业认定的税收优惠政策讲解
  19. 【PHPWord】PHPWord生成图表-雷达图 | 隐藏图例、设置数值类别隐藏、展示多组数据
  20. MATLAB08:符号运算

热门文章

  1. Hazelcast本地安装
  2. 怎么判断两个多项式互素_多项式互素性质的补充讨论
  3. 学习笔记 | Orillusion-WebGPU小白入门(六)
  4. 给视频加字幕HTML代码,一键添加字幕的软件推荐,几分钟学会给短视频加字幕,自媒体人都在用...
  5. 清华大学计算机陈蓓,清华大学2010级本科生新生代表座谈会举行
  6. Android 密钥库系统 (一)
  7. B. Disturbed People(模拟) Codeforces Round #521 (Div. 3)
  8. 嵌入式了解 以及学习路线
  9. [BZOJ3240][Noi2013]矩阵游戏 快速幂
  10. 进入pe系统 原系统启动服务器,pe和启动系统安装系统教程