前言
结合Glide讲文,做一篇Glide学习笔记
一、why使用Glide?
说说为什么使用Glide而不是其他图片加载框架?
- 使用简单三步即可,添加依赖-》添加权限-》glide.with(content).load(uri).into(imageView),再高级一点就可以设置图片显示参数等
- 生命周期自动绑定,可以根据绑定的Activity或者Fragment生命周期管理图片请求
- 高效缓存策略(Picasso只会缓存原始尺寸的图片,Glide缓存的是多种规格),两级内存,两级文件
- 支持多种图片格式(GIF、Webp、Jpg)
二、How使用Glide?
1.使用流程
这里简要介绍一下,市面上关于Glide的普通用法甚至进阶用法也很多
- 在AndroidManifest.xml文件 添加依赖
- 需网络请求,则打开网络请求权限
- 加载图片
glide.with( Content )
.load(uri)
.into(imageView
三、Glide关注要点
其中 主要关注的有这么几点
- Glide进行图片请求流程
- 三级缓存加载图片
- 网络获取图片流程
- Glide加载图片时,生命周期的绑定与管理
- Glide完成网络图片请求后,对数据进行缓存
- Glide缓存目的
- Glide缓存流程
1. Glide进行图片请求流程
- Glide #with 传入绑定组件(content、activity、fragment、view),获取与生命周期绑定的RequsetManager
- Glide #load 构造一个RequestBuilder实例,同时往RequestBuilder实例传入需要加载的数据源类型(file、uri、string、drawable、bitmap、resourceId)
- Glide #into RequestBuilder中指定图片最终加载位置,并且构建对应的Request、Target
- 最后在track方法中,将target加入到追踪队列中(用生命周期自动管理了request请求的开始、暂停和结束等操作),并执行request请求,进行图片请求
- 在(4)图片请求,request通过Engine分别尝试从活动缓存、Lru缓存、文件缓存中加载图片,当以上缓存中都不存在对应图片后,会进行网络获取
- 网络获取大致可以分成, ModelLoader模型匹配、DataFetcher数据获取,然后再进行解码、图片变换、转换。如果能够进行缓存原始数据,还会将解码的数据进行编码缓存到文件。
2. Glide生命周期绑定
(1) 从Glide.with(context)开始了解生命周期绑定流程
(1)with()方法 有多个重载,可以传入Context、Activity、Fragment、VIew等
Glide.with()
public static RequestManager with(@NonNull Context context) {
return getRetriever(context).get(context);
}
public static RequestManager with(@NonNull Activity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
public static RequestManager with(@NonNull Fragment fragment) {
return getRetriever(fragment.getActivity()).get(fragment);
}
public static RequestManager with(@NonNull View view) {
return getRetriever(view.getContext()).get(view);
}
(2)传入后 获得类 RequestManagerRetriever,并调用其get方法,具体 get方法如下:
RequestRetriever.get()
@NonNull
public RequestManager get(@NonNull FragmentActivity activity) {
if (Util.isOnBackgroundThread()) {
return get(activity.getApplicationContext());
} else {
assertNotDestroyed(activity);
//获取当前Activity的FragmentManager
//用于后续将创建的Fragment绑定到activity
FragmentManager fm = activity.getSupportFragmentManager();
return supportFragmentGet(activity, fm, null /*parentHint*/);
}
}
(3)在 get方法中判断是否在子线程中,在子线程中则调用 get 方法传入 activity.getApplicationContext() ,否则在主线程中:先创建FragmentManager类型的对象fm,再调用supportFragmentGet(),具体代码如下:
supportFragmentGet()
@NonNull
private RequestManager supportFragmentGet(@NonNull Context context, @NonNull FragmentManager fm,
@Nullable Fragment parentHint) {
//创建无UI的Fragment,并绑定到当前activity
SupportRequestManagerFragment current = getSupportRequestManagerFragment(fm, parentHint);
RequestManager requestManager = current.getRequestManager();
if (requestManager == null) {
// TODO(b/27524013): Factor out this Glide.get() call.
Glide glide = Glide.get(context);
//创建RequestManager,获取fragment的lifecycle,传入requestManager
requestManager =
factory.build(
glide, current.getGlideLifecycle(), current.getRequestManagerTreeNode(), context);
current.setRequestManager(requestManager);
}
return requestManager;
}
(4) 利用传入的context(也就是with.(context)中的context)和 fm 创建一个无UI的fragment对象 current ,类型为SupportRequestManagerFragment,再利用current创建一个RequestManager类型的requestManager,其中SupportRequestManagerFragment的具体代码如下:
SupportRequsetFragment()
public class SupportRequestManagerFragment extends Fragment {
private static final String TAG = "SupportRMFragment";
private final ActivityFragmentLifecycle lifecycle;
...
public SupportRequestManagerFragment() {
this(new ActivityFragmentLifecycle());
}
@VisibleForTesting
@SuppressLint("ValidFragment")
public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle) {
this.lifecycle = lifecycle;
}
@NonNull
ActivityFragmentLifecycle getGlideLifecycle() {
return lifecycle;
}
@Override
public void onStart() {
super.onStart();
lifecycle.onStart();
}
@Override
public void onStop() {
super.onStop();
lifecycle.onStop();
}
@Override
public void onDestroy() {
super.onDestroy();
lifecycle.onDestroy();
unregisterFragmentWithRoot();
}
}
(5) 在SupportRequestManagerFragment中,创建一个ActivityFragmentLifecycle类型的对象lifecycle,但具体进行操作做事的是lifecycle的方法,其中选取onStart方法,代码如下:
onStart()
void onStart() {
for (LifecycleListener lifecycleListener : Util.getSnapshot(lifecycleListeners)) {
lifecycleListener.onStart();
}
}
(6)在对应生命周期中调用lifecycle的生命周期方法,来通知LifecycleListener,但其实LifecycleListener类的子类就是RequstManager,从而达到了 先前创建的 无UI的Fragment 与 RequsetManager 通信,RequestManager的具体实现代码如下:
RequestManager
public class RequestManager implements LifecycleListener {
/**
* Lifecycle callback that registers for connectivity events (if the
* android.permission.ACCESS_NETWORK_STATE permission is present) and restarts failed or paused
* requests.
*/
@Override
public void onStart() {
resumeRequests();
}
/**
* Lifecycle callback that unregisters for connectivity events (if the
* android.permission.ACCESS_NETWORK_STATE permission is present) and pauses in progress loads.
*/
@Override
public void onStop() {
pauseRequests();
}
/**
* Lifecycle callback that cancels all in progress requests and clears and recycles resources for
* all completed requests.
*/
@Override
public void onDestroy() {
...
requestTracker.clearRequests();
}
}
小结:(1)当我们从 Glide.with(coutext)开始,根据传入的参数,调用对应的重载方法,具体操作为:创建一个RequestManager对象并调用其get方法
(2)在get方法中,判断是否在子线程中
(3)不在子线程中,则创建一个Fragment类型的对象fm, 并调用 supportFragmentGet方法,将 context 和 fm 传入
(4)在supportFragmentGet方法中,创建一个 SupportRequestManagerFragment类型的对象current
1)在对象current生命周期方法中,实际调用的是lifecycle的生命周期方法,而在lifecycle的生命周期方法中,实现与lifecycleListener的通信,而lifecycleListener的子类
就是RequestManager
2)再利用 current.getRequesrManager方法创建一个RequstManager对象
3)再判断RequstManager对象是否为空,若为 空,则传入 context,创建 glide对象,使用factory.build绑定current,从而实现生命周期绑定
(2)生命周期时长
虽然with方法有多个重载,但是其实可以根据glide.with(context)传入的参数是否为Application类型参数,分为两种情况
- 传入Application Context或者在 get方法中判断在子线程中使用 :调用getApplicationManager(context); 这样 Glide的生命周期就和应用程序一样,因为相比于 传入Activity、Fragment对象,因为获取的是ApplicationLifecycle,不创建Fragment,所以只会调用onStart方法
- 其他情况,比如传入Activity、Fragment等:调用 supportFragmentGet方法, Glide就会在生命周期不同的方法中对请求做不同处理,
(3)总结
- Glide关联生命周期大致分为两部分
- 与组件绑定(通过创建一个无UI的Fragment对象 current)
- 传递生命周期(RequstManager与Fragment之间通过LifeCycle、LifecycleListener接口回调实现)
- Glide.with()方法,使用glide.with(getApplicationContext()),则生命周期与应用程序一样,传入Activitiy或Fragment ,才可以绑定关联组件生命周期
- 在UI线程中调用Glide、子线程中使用Glide和使用 ApplicationContext一样
3. Glide缓存管理
Glide缓存 分为两部分:内存缓存(弱引用(weakReference)+Lrucache)+硬盘缓存(DiskLrucache,与Lrucache差不多),所以常说三级缓存是 weakReference --> Lrucache --> DiskLrucache
(1)引入缓存目的
- 减少流量消耗,加快响应速度
- 使用缓存可以更加高效的加载Bitmap,减少卡顿
(2)缓存流程
取顺序:弱引用 -->Lrucache -->DiskLrucache -->网络
写顺序:DiskLrucache -->弱引用,当计数器为0 的时候,再放到Lrucache中
(3)缓存原理
- 弱引用
- 底层数据结构:HashMap ,key是缓存的key,由uri,width,height等参数组成;value是图片资源对象的弱引用形式
- LruCache
- 底层数据结构:linkedHashMap,LRU Least Recently Used的缩写,最近最少使用置换算法,而LinkHashMap链表则是把最近使用过的文件插到列表头部,未使用的图片放到尾部
- 存取原理
- 在内存缓存中由一个概念叫图片引用计数器,是在EngineResource中定义一个acquired变量用来记录图片被引用的次数,调用acquire()方法会让变量加1,调用release()方法会让变量减1
- 获得图片资源
-
首先从弱引用取缓存,拿到则计数+1;没拿到则从Lrucache中拿缓存,拿则计数+1,同时把图片从Lrucache缓存转移到弱引用缓存中;没拿到的话,九通过EngineJob开启线程池取加载图片,拿到的话计数+1,并把图片放到弱引用缓存中
-
- 存数据
- 在加载图片之后,可以把图片数据缓存下来,通过EngineJob开启线程池取加载图片,取到数据后再回调主线程,把图片存到弱引用中,当图片不再使用时,比如暂停请求或者加载完毕或者清除资源时,就会将其从弱引用中转移到LruCache中
- 引入弱引用作用
- 提高效率
(4)手写Lrucache
待续...
(5)磁盘缓存
1. 如果再内存缓存(弱引用+Lrucache)中没拿到数据,就通过EngineJob开启线程池去加载图片,通过 EngineJob内部维护线程池,用来管理资源加载,当资源加载完成后通知回调;DecodeJob是线程池中的一个任务
2. 磁盘缓存是通过DiskLrucache来管理,根据缓存策略分为两种类型的图片:DATA(原始图片)和 RESOURCE(转换后图片)。
3. 磁盘缓存依次通过
1. ResourceCacheGenerator(获取转换后的缓存数据)
2. SourceCacheGenerator(获取未经转换的原始缓存数据)
3. DataCacheGenerator(通过网络获取图片数据,再按照不同缓存策略去缓存不同图片到磁盘上)来获取缓存数据
总结
对Glide生命周期进行学习总结,并了解Glide加载缓存流程
Glide中Lrucache的手写后续补上