Glide实现原理解析

更新时间:2023-06-30 00:08:39 阅读: 评论:0

Glide实现原理解析
⼀.Glide缓存机制
Glide采取的多级缓存机制,能够较为友好地实现图⽚、动图的加载。其主要有 内存缓存+磁盘缓存 ,当然他们的作⽤也有不同,其中内存缓存主要⽤于防⽌将重复的图读⼊内存中,磁盘缓存则⽤于防⽌从⽹络或者其他地⽅将重复下载和数据读取。
默认情况下,Glide 会在开始⼀个新的图⽚请求之前检查以下多级的缓存:
1. 活动资源 (Active Resources)
2. 内存缓存 (Memory Cache)
3. 资源类型(Resource Disk Cache)
4. 原始数据 (Data Disk Cache)
腊排骨炖萝卜
活动资源:如果当前对应的图⽚资源正在使⽤,则这个图⽚会被Glide放⼊活动缓存。
内存缓存:如果图⽚最近被加载过,并且当前没有使⽤这个图⽚,则会被放⼊内存中
资源类型: 被解码后的图⽚写⼊磁盘⽂件中,解码的过程可能修改了图⽚的参数(如:inSampleSize。inPreferredConfig)
原始数据: 图⽚原始数据在磁盘中的缓存(从⽹络、⽂件中直接获得的原始数据)
在调⽤into之后,Glide会⾸先从Active Resources查找当前是否有对应的活跃图⽚,没有则查找内存缓存,没有则查找资源类型,没有则查找数据来源。
1.活动资源
活动资源中是⼀个”引⽤计数"的图⽚资源的弱引⽤集合。使⽤⼀个 Map<Key, WeakReference<EngineResource<?>>> 来存储的。
此外还有⼀个引⽤队列ReferenceQueue<EngineResource<?>> resourceReferenceQueue;每当向 activeResource 中添加⼀个WeakReference 对象时都会将 resourceReferenceQueue 和这个 WeakReference 关联起来,⽤来跟踪这个 WeakReference 的gc,⼀旦这个弱引⽤被 gc 掉,就会将它从 activeResource 中移除。
ReferenceQueue 具体是在何时去判断 WeakReference 是否被 gc 了呢?
⽼版本调⽤ MessageQueue#addIdleHandler 添加⼀个 MessageQueue.IdleHandler 对象,Handler 会在线程空闲时调⽤这个⽅法。
新版本开启⼀个线程,使⽤handler发送消息判断
当需要加载某张图⽚能够从内存缓存中获得的时候,在图⽚加载时主动将对应图⽚从内存缓存中移除,加⼊到活动资源中。
这样也可以避免因为达到内存缓存最⼤值或者系统内存压⼒导致的内存缓存清理,从⽽释放掉活动资源中的图⽚(recycle)。
因为同⼀张图⽚可能在多个地⽅被同时使⽤,每⼀次使⽤都会将引⽤计数+1,⽽当引⽤计数为0时候,则表⽰这个图⽚没有被使⽤也就是没有强引⽤了。这样则会将图⽚从活动资源中移除,并加⼊内存缓存。
2.内存缓存
内存缓存默认使⽤LRU(缓存淘汰算法/最近最少使⽤算法),当资源从活动资源移除的时候,会加⼊此缓存。使⽤图⽚的时候会主动从此缓存移除,加⼊活动资源。LRU在Android support-v4中提供了LruCache⼯具类。
3.磁盘缓存
资源类型缓存的是经过解码后的图⽚,如果再使⽤就不需要再去进⾏解码配置(BitmapFactory.Options),加快获得图⽚速度。⽐如原图是⼀个100x100的ARGB_8888图⽚,在⾸次使⽤的时候需要的是50x50的RGB_565图⽚,那么Resource将50x50 RGB_565缓存下来,再次使⽤此图⽚的时候就可以从 Resource 获得。不需要去计算inSampleSize(缩放因⼦)。
原始数据缓存的则是图像原始数据。
Bitmap复⽤池
如果缓存都不存在,那么会从源地址获得图⽚(⽹络/⽂件)。⽽在解析图⽚的时候会需要可以获得BitmapPool(复⽤池),达到复⽤的效果。复⽤并不能减少程序正在使⽤的内存⼤⼩。Bitmap复⽤,解决的是减少频繁申请内存带来的性能(抖动、碎⽚)问题。
BitmapPool是Glide中的Bitmap复⽤池,同样适⽤LRU来进⾏管理。在每次解析⼀张图⽚为Bitmap的时候(磁盘缓存、⽹络/⽂件)会从其BitmapPool中查找⼀个可被复⽤的Bitmap。当⼀个Bitmap从内存缓存 被动 的被移除(内存紧张、达到maxSize)的时候并不会被recycle。⽽是加⼊这个BitmapPool,只有从这个BitmapPool 被动的被移除的时候,Bitmap的内存才会真正被recycle释放。
Bitmap复⽤⽅式为在解析的时候设置Options的inBitmap属性。
1. Bitmap的inMutable需要为true。
2. Android 4.4及以上只需要被复⽤的Bitmap的内存必须⼤于等于需要新获得Bitmap的内存,则允许复⽤此Bitmap。
3. 4.4以下(3.0以上)则被复⽤的Bitmap与使⽤复⽤的Bitmap必须宽、⾼相等并且使⽤复⽤的Bitmap解码时设置的inSampleSize为1,才允许复⽤。⼆.Glide⽣命周期管理
Glide在Glide.with(context)中就实现了⽣命周期管理,with根据传⼊的参数有不同的实现。
//传⼊⼀个Context
public static RequestManager with(@NonNull Context context)
//传⼊⼀个activity
public static RequestManager with(@NonNull Activity activity)
//传⼊⼀个FragmentActivity
public static RequestManager with(@NonNull FragmentActivity activity)
//传⼊⼀个Fragment
public static RequestManager with(@NonNull Fragment fragment)
//传⼊⼀个View
public static RequestManager with(@NonNull View view)
虽然有这么多类型,但其实可以分为两类的。
传⼊⼀个ApplicationContext,Glide的⽣命周期就相当于绑定了整个应⽤,只要应⽤不退出,任何时候都能够加载,也可以理解为不对Glide⽣命周期进⾏管理。
传⼊activity、FragmentActivity 、Fragment 及View ,这样就会创建⼀个看不见的fragment,Glide的⽣命周期就随着该Fragment的变化⽽变化。
当传⼊参数为ApplicationContext时,代码实现如下。
电脑怎么扫描文件public static RequestManager with(@NonNull Context context){
return getRetriever(context).get(context);
}
//由于传⼊参数是ApplicationContext,所以最终调⽤getApplicationManager⽅法。
public RequestManager get(@NonNull Context context){
if(context == null){
throw new IllegalArgumentException("You cannot start a load on a null Context");
}el if(Util.isOnMainThread()&&!(context instanceof Application)){
if(context instanceof FragmentActivity){
//判断context类型是不是FragmentActivity
return get((FragmentActivity) context);
}el if(context instanceof Activity){
/
/判断context类型是不是Activity
return get((Activity) context);
经纬网练习题}el if(context instanceof ContextWrapper){
//判断context类型是不是ContextWrapper
return get(((ContextWrapper) context).getBaContext());
}
}
//context类型属于ApplicationContext
return getApplicationManager(context);
}
由于传⼊参数是ApplicationContext,所以最终调⽤getApplicationManager⽅法。
private RequestManager getApplicationManager(@NonNull Context context){
// Either an application context or we're on a background thread.
if(applicationManager == null){
synchronized(this){
if(applicationManager == null){
Glide glide = (ApplicationContext());
applicationManager =
factory.build(
glide,
new ApplicationLifecycle(),
new EmptyRequestManagerTreeNode(),
}
}
}
return applicationManager;
}
这⾥就直接创建⼀个ApplicationLifecycle来管理⽣命周期,但ApplicationLifecycle并不受控制,所以就⽆法对Glide⽣命周期进⾏管理。 以传⼊参数类型为Activity为例,代码实现如下。
不念过去不畏将来public static RequestManager with(@NonNull Activity activity){
return getRetriever(activity).get(activity);
}
public RequestManager get(@NonNull Activity activity){
//如果在⼦线程,则不对Glide⽣命周期就那些管理
if(Util.isOnBackgroundThread()){
return ApplicationContext());
}el{
asrtNotDestroyed(activity);
//拿到FragmentManager对象
android.app.FragmentManager fm = FragmentManager();
//获取fragment对象,并返回⼀个RequestManager 对象
return fragmentGet(
activity, fm,/*parentHint=*/ null,isActivityVisible(activity));
}
}
如果当前是在⼦线程,则不需要对Glide⽣命周期进⾏管理,否则将通过fragmentGet⽅法创建⼀个fragment。
private RequestManager fragmentGet(@NonNull Context context,
@NonNull android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible){
//创建⼀个fragment对象
RequestManagerFragment current =getRequestManagerFragment(fm, parentHint, isParentVisible);
RequestManager requestManager = RequestManager();
if(requestManager == null){
// TODO(b/27524013): Factor out () call.
//防⽌Glide对象被异常回收
Glide glide = (context);
//创建⼀个RequestManager对象
requestManager =
factory.build(
glide, GlideLifecycle(), RequestManagerTreeNode(), context);
current.tRequestManager(requestManager);
}
return requestManager;
}
在该⽅法中,通过getRequestManagerFragment来获得⼀个Fragment对象。然后拿到该Fragment对
应的RequestManager 对象,如果该对象为null则创建⼀个RequestManager对象并将fragment中的ActivityFragmentLifecycle对象传递给RequestManager。先来看getRequestManagerFragment⽅法的实现。
private RequestManagerFragment getRequestManagerFragment(
@NonNull final android.app.FragmentManager fm,
@Nullable android.app.Fragment parentHint,
boolean isParentVisible){
//查找tag为FRAGMENT_TAG的fragment
RequestManagerFragment current =(RequestManagerFragment) fm.findFragmentByTag(FRAGMENT_TAG);
if(current == null){
//从HashMap中取出fm
current = (fm);
if(current == null){
//创建fragment对象
current =new RequestManagerFragment();
//当fragment嵌套fragment时才会使⽤,否则parentHint是null
current.tParentFragmentHint(parentHint);
if(isParentVisible){
//开始执⾏请求
}
护眼小妙招
//将fm添加到HashMap中,防⽌fragment的重复创建
pendingRequestManagerFragments.put(fm, current);
//添加fragment
fm.beginTransaction().add(current, FRAGMENT_TAG).commitAllowingStateLoss();
//从HashMap集合从移除fm
handler.obtainMessage(ID_REMOVE_FRAGMENT_MANAGER, fm).ndToTarget();
}
}
return current;
}
从fm中去查找tag为FRAGMENT_TAG的fragment是否存在,如果不存在就从pendingRequestManagerFragments这个HashMap中去取,如果没有就创建⼀个fragment,添加到pendingRequestManagerFragments并且将该fragment绑定到activity,绑定成功后则从pendingReque
stManagerFragments移除fragment。这⾥的pendingRequestManagerFragments主要是防⽌fragment重复创建(Glide⽣命周期管理),因为每个activity必须对应⼀个唯⼀的fragment。来看⼀下这个fragment的实现RequestManagerFragment。
public class RequestManagerFragment extends Fragment {
private final ActivityFragmentLifecycle lifecycle;
public SupportRequestManagerFragment(){柯赐海
this(new ActivityFragmentLifecycle());
}
public SupportRequestManagerFragment(@NonNull ActivityFragmentLifecycle lifecycle){
this.lifecycle = lifecycle;
}
...
@NonNull
ActivityFragmentLifecycle getGlideLifecycle(){
return lifecycle;
}
...
@Override
public void onStart(){
}
@Override
红楼梦朝代
public void onStop(){少年闰土小练笔
}
@Override
public void onDestroy(){
unregisterFragmentWithRoot();
}
...
}
再回到fragmentGet⽅法,fragment创建成功后,在创建RequestManager时会传⼊fragment中的ActivityFragmentLifecycle,再来看RequestManager的实现。
public class RequestManager implements LifecycleListener,
ModelTypes<RequestBuilder<Drawable>>{
private final Runnable addSelfToLifecycle =new Runnable(){
@Override
public void run(){
lifecycle.addListener(RequestManager.this);
}
};
public RequestManager(
@NonNull Glide glide,@NonNull Lifecycle lifecycle,
@NonNull RequestManagerTreeNode treeNode,@NonNull Context context){
this(
glide,
lifecycle,
treeNode,
new RequestTracker(),
context);
}
// Our usage is safe here.
@SuppressWarnings("PMD.ConstructorCallsOverridableMethod")
RequestManager(
Glide glide,
Lifecycle lifecycle,
RequestManagerTreeNode treeNode,
RequestTracker requestTracker,

本文发布于:2023-06-30 00:08:39,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/82/1069223.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:缓存   内存   时候   对象   没有   获得
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图