前言
近期研究了一下Glide的图片加载框架,在这里和大家分享一下。由于代码研读有限,难免有错误的地方,了解的童鞋还望指正。
本篇是Glide框架及源码解析的第二篇,更多文章敬请关注后续文章。如果这篇文章对大家学习Glide有帮助,还望大家多多转载。
版权归作者所有,如有转发,请注明文章出处:http://www.jianshu.com/u/d43d948bef39
相关文章:
跟着源码学设计:Glide框架及源码解析(一)
跟着源码学设计:Glide框架及源码解析(二)
跟着源码学设计:Glide框架及源码解析(三)
跟着源码学设计:Glide框架及源码解析(四)
跟着源码学设计:Glide框架及源码解析(五)
1. Request管理机制
在上一篇中我们剖析了Glide的生命周期绑定机制,这一篇我们紧接着Glide的处理流程来学习一下Glide的请求管理机制。
我们先来看一下Glide的最简单的使用代码示例:
ImageView ivImage = (ImageView) findViewById(R.id.ivImage);
Glide.with(ivImage.getContext()) //获取RequestManager对象
.load(url); //设置Request对象需要的资源链接
.into(ivImage); //获取Request对象并绑定viewTarget -> 发起网络请求
该段代码十分简洁,但是内部实现的功能却十分的强大,比如:
- request的生命周期管理(如:退出或者隐藏了界面,需求就取消或暂停了)
- viewTarget的生命周期管理
- 资源的复用和释放
- 灵活的配置(request的builder模式)
针对这些问题,后面将会一一展开剖析。
2. request及其生命周期管理
- 通过上一篇的学习,我们知道了Glide内部生命周期接口为LifecycleListener
- RequestManager具有生命周期(实现了LifecycleListener接口)
- request由RequestManager的into()方法族获得
- request的生命周期由RequestManager统一管理
3. Glide请求管理机制类图
RequestManager是如何生成request并管理request队列的?
老规矩,先上图:
如图:
- RequestManager持有一个RequestTracker对象requestTracker。
- requestTracker对象维护request的队列集合
- RequestManager的load()函数用于获取GenericRequestBuilder对象(其实是子类对象)
- load()内部调用loadGeneric()方法,将requestTracker对象引用传递给GenericRequestBuilder类
- load()实际调用GenericRequestBuilder.load()方法完成request的URL设置
- GenericRequestBuilder的into()方法是实际产生request和消费request的地方。
- GenericRequestBuilder的into(target)方法调用obtainReauest()获取到GenericRequest对象request,request与target相互绑定并被requestTracker维护。
3.1 GenericRequestBuilder的into(target)方法
public <Y extends Target<TranscodeType>> Y into(Y target) {
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
//因为target和request是相互绑定的,所以考虑到复用的情景时,可以先获取一下request
Request previous = target.getRequest();
//previous != null说明target有复用,需要释放之前绑定的资源
//注意:request内部是绑定了资源的,这里还没有讲到,先知道这回事,后面会讲
if (previous != null) {
//释放资源,防内存泄漏
//这段代码是精华,需要好好体会:
//Glidek肯定支持view的复用(对吧?),那么复用的view资源是如何绑定和释放的?
//这里就是资源释放的地方(入口),资源在何时绑定会在后续的课程讲到。
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
//获取需求对象(对象绑定了target)
Request request = buildRequest(target);
//target绑定需求
target.setRequest(request);
//因为target具有生命周期,即实现了LifecycleListener方法,所以将其注册给ActivityFragmentLifecycle统一管理(不知道是啥的去看上一篇文章)
lifecycle.addListener(target);
//将需求加入队列并执行需求
//注意是单线程
requestTracker.runRequest(request);
return target;
}
3.2 request的生命周期管理
- 根据上文得知,request都被加入到requestTracker中来管理
- requestTracker由RequestManager创建和管理
- RequestManager具有生命周期
3.2.1 RequestManager
下面让我们看看RequestManager在各个生命周期回调里都做了什么
@Override
public void onStart() {
resumeRequests();
}
@Override
public void onStop() {
pauseRequests();
}
@Override
public void onDestroy() {
requestTracker.clearRequests();
}
public void pauseRequests() {
Util.assertMainThread();
requestTracker.pauseRequests();
}
public void resumeRequests() {
Util.assertMainThread();
requestTracker.resumeRequests();
}
//下面的两个回调其实和request的关系没有那么直接,先放在这里留个印象
public void onTrimMemory(int level) {
glide.trimMemory(level);
}
public void onLowMemory() {
glide.clearMemory();
}
代码很清楚了吧。细心的同学可能注意到了onTrimMemory(int level)和onLowMemory(),这俩货是系统在资源不足时调用的,说白了就是释放内存,具体怎么搞得,后续文章会专门讲到Glide的内存管理机制(也是精华)
3.2.2 requestTracker
最后让我们看看requestTracker都干啥了吧
public class RequestTracker {
private final Set<Request> requests = Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
private final List<Request> pendingRequests = new ArrayList<Request>();
private boolean isPaused;
/**
* Starts tracking the given request.
*/
public void runRequest(Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
// Visible for testing.
void addRequest(Request request) {
requests.add(request);
}
/**
* Stops tracking the given request.
*/
public void removeRequest(Request request) {
requests.remove(request);
pendingRequests.remove(request);
}
/**
* Returns {@code true} if requests are currently paused, and {@code false} otherwise.
*/
public boolean isPaused() {
return isPaused;
}
/**
* Stops any in progress requests.
*/
public void pauseRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.pause();
pendingRequests.add(request);
}
}
}
/**
* Starts any not yet completed or failed requests.
*/
public void resumeRequests() {
isPaused = false;
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCancelled() && !request.isRunning()) {
request.begin();
}
}
pendingRequests.clear();
}
/**
* Cancels all requests and clears their resources.
*/
public void clearRequests() {
for (Request request : Util.getSnapshot(requests)) {
request.clear();
}
pendingRequests.clear();
}
/**
* Restarts failed requests and cancels and restarts in progress requests.
*/
public void restartRequests() {
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCancelled()) {
// Ensure the request will be restarted in onResume.
request.pause();
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
}
}
}
(本篇是Glide框架及源码解析的第二篇,更多文章敬请关注后续文章。版权归作者所有,如有转发,请注明文章出处:原文链接)