欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-02-29 13:40:46
0.基础知识 glide中有一部分单词,我不知道用什么中文可以确切的表达出含义,用英文单词可能在行文中更加合适,还有一些词在glide中有特别的含义,我理解的可能也不深入...

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. 总体设计

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

基本概念
requestmanager:请求管理,每一个activity都会创建一个requestmanager,根据对应activity的生命周期管理该activity上所以的图片请求。
engine:加载图片的引擎,根据request创建enginejob和decodejob。
enginejob:图片加载。
decodejob:图片处理。
流程图
这里是大概的总体流程图, 具体的细节中流程下面继续分析。

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

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。

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

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加速内存回收。