转载请注明出处:王亟亟的大牛之路
写之前先安利,接下来2 3个月我会花点时间捡起一些安卓的技能,看看这2年没花什么精力投入的安卓变成啥样子了https://github.com/ddwhan0123/Useful-Open-Source-Android
什么是Glide?
Glide是一个快速高效的Android图片加载库,注重于平滑的滚动。Glide提供了易用的API,高性能、可扩展的图片解码管道(decode pipeline),以及自动的资源池技术。
Glide 支持拉取,解码和展示视频快照,图片,和GIF动画。Glide的Api是如此的灵活,开发者甚至可以插入和替换成自己喜爱的任何网络栈。默认情况下,Glide使用的是一个定制化的基于HttpUrlConnection的栈,但同时也提供了与Google Volley和Square OkHttp快速集成的工具库。
虽然Glide 的主要目标是让任何形式的图片列表的滚动尽可能地变得更快、更平滑,但实际上,Glide几乎能满足你对远程图片的拉取/缩放/显示的一切需求。
本篇研究的内容和目的
- Glide如何暂停请求
- Glide如何获取生命周期
- 以上二者是如何实现的
入口方法
Glide.with(this).load(img_url).into(imageView)
简单的一句加载函数
.with()
关联了一个上下文环境的对象
.load()
关联了你要加载的资源的路径(load是一个多态的方法,可以是url,字符串地址,文件等等等方式)
.into()
是把以上的内容加载到哪个控件里去(into()方法也是,面向的是ViewTarget<a,b>的泛形)
with的做了什么
所有with方法都返回了一个RequestManager
对象
RequestManager的get方法会根据不同的入参类型去构建RequestManager
对象(以下以Activity的场景为例)
@NonNull
public RequestManager get(@NonNull Activity activity) {
//判断是否在前台,否则调用更大引用周期的上下文对象
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
//有效生命周期内才继续初始化流程
assertNotDestroyed(activity);
android.app.FragmentManager fm = activity.getFragmentManager();
//传入4个参数上下文对象,activity的FragmentManager实现,空,true(是否前台可见)
return fragmentGet(
activity, fm, /*parentHint=*/ null, isActivityVisible(activity));
}
}
fragmentGet方法是实质构建RequestManager对象的方法,无论如何不会为空返回
@Deprecated
@NonNull
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible) {
RequestManagerFragment current = getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
RequestManager
我们来看一下这个类的源码,看下他是如何实现的。
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>> {}
实现了LifecycleListener
接口,也就是onDestroy,onStart,onStop
几个方法的回调都能拿到,可以在其中实现自己的业务逻辑
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,
ConnectivityMonitorFactory factory,
Context context) {
this.glide = glide;
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
this.context = context;
//网络状态的监听
connectivityMonitor =
factory.build(
context.getApplicationContext(),
new RequestManagerConnectivityListener(requestTracker));
//不同的上下文生命周期使用不同的监听
if (Util.isOnBackgroundThread()) {
mainHandler.post(addSelfToLifecycle);
} else {
lifecycle.addListener(this);
}
lifecycle.addListener(connectivityMonitor);
defaultRequestListeners =
new CopyOnWriteArrayList<>(glide.getGlideContext().getDefaultRequestListeners());
setRequestOptions(glide.getGlideContext().getDefaultRequestOptions());
//glide整个的请求管理托付于这个类
glide.registerRequestManager(this);
}
构造函数获取了Glide和之前由最外层context初始化的RequestManagerFragment的一些属性,当然初始化的时候还有一些静态内部的常量,构建了RequestOptions的一些属性
接下来看一下这个类实现了哪些功能(只解释跟我们主题相关的)
判断当前上下文对象的生命周期是否处于暂停状态
public synchronized boolean isPaused() {
return requestTracker.isPaused();
}
暂停正在执行中的请求
public synchronized void pauseRequests() {
requestTracker.pauseRequests();
}
暂停请求,且清楚已完成的加载内容
public synchronized void pauseAllRequests() {
requestTracker.pauseAllRequests();
}
恢复所有未完成的请求
public synchronized void resumeRequests() {
requestTracker.resumeRequests();
}
@Override
public synchronized void onStart() {
//恢复请求
resumeRequests();
targetTracker.onStart();
}
@Override
public synchronized void onStop() {
//暂停请求
pauseRequests();
targetTracker.onStop();
}
回收资源,移除监听
@Override
public synchronized void onDestroy() {
targetTracker.onDestroy();
for (Target<?> target : targetTracker.getAll()) {
clear(target);
}
targetTracker.clear();
requestTracker.clearRequests();
lifecycle.removeListener(this);
lifecycle.removeListener(connectivityMonitor);
mainHandler.removeCallbacks(addSelfToLifecycle);
glide.unregisterRequestManager(this);
}
这里看到RequestTracker其实是RequestManager实现的代理。我们找了3层终于了具体实现生命周期回调,和调用终止/恢复请求的地方。
RequestTracker
没有带参的构造函数,内部维护了请求队列
public class RequestTracker {
private static final String TAG = "RequestTracker";
private final Set<Request> requests =
Collections.newSetFromMap(new WeakHashMap<Request, Boolean>());
private final List<Request> pendingRequests = new ArrayList<>();
private boolean isPaused;
}
在调用into()方法后会被执行,Request是个接口,实现了请求,取消,暂停等功能方法
public void runRequest(@NonNull Request request) {
requests.add(request);
if (!isPaused) {
request.begin();
} else {
request.clear();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "Paused, delaying request");
}
pendingRequests.add(request);
}
}
暂停请求,并回收
public boolean clearRemoveAndRecycle(@Nullable Request request) {
return clearRemoveAndMaybeRecycle(request, /*isSafeToRecycle=*/ true);
}
在初次启动请求时会设置为false,是否暂停请求的控制flag
public boolean isPaused() {
return isPaused;
}
在容器生命周期onStop()回调中恢复请求暂停请求
public void pauseRequests() {
isPaused = true;
for (Request request : Util.getSnapshot(requests)) {
if (request.isRunning()) {
request.clear();
pendingRequests.add(request);
}
}
}
在容器生命周期onStart()回调中恢复请求
public void resumeRequests() {
isPaused = false;
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isRunning()) {
request.begin();
}
}
pendingRequests.clear();
}
清除请求并回收,在上下文生命周期的onDestroy()处调用
public void clearRequests() {
for (Request request : Util.getSnapshot(requests)) {
clearRemoveAndMaybeRecycle(request, /*isSafeToRecycle=*/ false);
}
pendingRequests.clear();
}
在网络监听到连接的状态下,重新请求,包括失败的/暂停的/进行中的
public void restartRequests() {
for (Request request : Util.getSnapshot(requests)) {
if (!request.isComplete() && !request.isCleared()) {
request.clear();
if (!isPaused) {
request.begin();
} else {
pendingRequests.add(request);
}
}
}
}
总结
第一步:with方法挂载上下文对象用以获取他的生命周期,并初始化RequestManager对象。
第二部:RequestManager对象初始化了RequestOptions,以及实现一系列生命周期与业务逻辑相关联的方法,并且实现了.load()方法,把资源方面的实现与上下文相关业务实现分离。
第三部:RequestManager用自己的代理实现RequestTracker类维护了未完成和完成两个任务队列,通过Request接口分别实行不同的业务方法
简要知识点:
调用into()方法后才会开始执行业务请求
网络状态已经实现监听,业务端不用自己监听后调用clear()
Glide网络监听接口只区分断没断网,不管理网络类型(暂未发现对4g/3g/2g/wifi等场景的特殊处理)
其他
有问题欢迎沟通,但请注明来意