glide问题之复习

一.glide的简介

1.1 使用方法?
with():
1,主要就是配置glide绝大部分信息并向当前的Activity当中添加一个隐藏无UI的Fragment,这个特殊的Fragment持有一个Lifecycle。通过Lifecycle通知RequestManger进行相关的操作并且最终返回一个requsetManager对象执行load方法。


load():
load过程就是收集配置信息,最终返回RequestBuilder对象,通过这个对象我们就可以根据传入的mode是url还是本地文件或者其他的资源,然后获得图片请求的request,方便在into方法中使用。


into(): 构建具体图片加载对象并通过Engine这个核心类加载出来。

1.2 glide优点:
1.Glide 支持多种图片格式的缓存如 Gif、WebP、缩略图、Video。


2.与Activity或Fragment生命周期绑定,不会出现内存泄露-生命周期集成(根据Activity或者Fragment生命周期管理图片加载请求)


3.高效的缓存策略:三级缓存
3.高效的缓存策略,灵活(Picasso只会缓存原始尺寸图片,Glide缓存是多种规格),加载速度快且内存开销小(默认Bitmap格式不同,使得内存开销是Picasso一半)
4.高效处理Bitmap(bitmap的复用和主动回收,减少系统回收压力)
。Picasso只会缓存原始尺寸的图片,而glide不同,为每个不同尺寸Imageview缓存一张图片,即不管这张图片有没有加载过,只要imageview尺寸不一样,Glide就会重新加载一次
5.内存开销小:RGB是最小格式。
6.使用简单方便,链式调用;

glide的优势
• 多种图片格式的缓存,适用于更多的内容表现形式(如Gif、WebP、缩略图、Video)
• 生命周期集成(根据Activity或者Fragment的生命周期管理图片加载请求)
• 高效处理Bitmap(bitmap的复用和主动回收,减少系统回收压力)
• 高效的缓存策略,灵活(Picasso只会缓存原始尺寸的图片,Glide缓存的是多种规格),加载速度快且内存开销小(默认Bitmap格式的不同,使得内存开销是Picasso的一半)

1.3 相比其他图片加载库(Picasso & Fresco)
  对比Picasso:
Glide RGB格式更小内存开销更少,picasso缓存原图,glide缓存的是跟ImageView尺寸相同的。
glide可以加载gif,WebP、缩略图。

   
对比Fresco:
Fresco将图片放到一个特别的内存区域,可以大大减少OOM(在更底层的Native层对OOM进行处理,图片将不再占用App的内存)但是fresco包体积较大
对于一般App来说,Glide完全够用,而对于图片需求比较大的App,为了防止加载大量图片导致OOM,Fresco 会更合适一些。在红星图片使用场景很多的地方就是fresco 。

二. glide介绍?
1.1 生命周期绑定:
Glide通过在当前Activity/Fragment里添加一个Fragment,在Fragment的生命周期里回调LifecycleListener的相应方法,而RequestManager实现了该接口,所以就可以在相应的生命周期执行请求的开始和暂停等操作。

Glide原理:
• Glide在加载绑定了Activity的生命周期。
• 在Activity内新建一个无UI的Fragment,这个特殊的Fragment持有一个Lifecycle。通过Lifecycle在Fragment关键生命周期通知RequestManger进行相关的操作。
• 在生命周期onStart时继续加载,onStop时暂停加载,onDestory是停止加载任务和清除操作。

Glide原理
• Glide在加载绑定了Activity的生命周期。
• 在Activity内新建一个无UI的Fragment,这个特殊的Fragment持有一个Lifecycle。通过Lifecycle在Fragment关键生命周期通知RequestManger进行相关的操作。
• 在生命周期onStart时继续加载,onStop时暂停加载,onDestory是停止加载任务和清除操作。
生命周期绑定
Glide通过在当前Activity/Fragment里添加一个Fragment,在Fragment的生命周期里回调LifecycleListener的相应方法,而RequestManager实现了该接口,所以就可以在相应的生命周期执行请求的开始和暂停等操作。

图片加载策略:

• 首先从ActivateResource获取,是个值为弱引用的Map
• MemoryCache和DiskCache是LruCache

1.2  缓存?
三级缓存:内存缓存、硬盘缓存、网络

内存缓存 LruCache?
LruCache 采用最近最少使用算法,设定一个缓存大小,当缓存达到这个大小之后,会将最老的数据移除,避免图片占用内存过大导致OOM。
• LinkHashMap 继承HashMap,在 HashMap的基础上,新增了双向链表结构,每次访问数据的时候,会更新被访问的数据的链表指针,具体就是先在链表中删除该节点,然后添加到链表头header之前,这样就保证了链表头header节点之前的数据都是最近访问的(从链表中删除并不是真的删除数据,只是移动链表指针,数据本身在map中的位置是不变的)。

 面put数据的时候,当数据达到最大内存的时候,将最老的数据移除掉,保证内存不超过设定的最大值。
• LruCache 内部用LinkHashMap存取数据,在双向链表保证数据新旧顺序的前提下,设置一个最大内存,往里面put数据的时候,当数据达到最大内存的时候,将最老的数据移除掉,保证内存不超过设定的最大值。

LRUCache原理:

blog.csdn.net/u010983881/…

LruCache和 DiskLruCache

LruCache是Android 3.1所提供的一个缓存类。DisLruCache目前在Android还不是Android SDK的一部分,但Android官方文档推荐使用该算法来实现硬盘缓存。

LinkedHashMap 它使用了一个双向链表来存储Map中的Entry顺序关系,这种顺序有两种,一种是LRU顺序,一种是插入顺序

put()重要的就是在添加过缓存对象后,调用trimToSize()方法,来判断缓存是否已满,如果满了就要删除近期最少使用的算法。

trimToSize()方法不断地删除LinkedHashMap中队头的元素,即近期最少访问的,直到缓存大小小于最大值

LruCache中维护了一个集合LinkedHashMap,该LinkedHashMap是以访问顺序排序的。当调用put()方法时,就会在结合中添加元素,并调用trimToSize()判断缓存是否已满,如果满了就用LinkedHashMap的迭代器删除队头元素,即近期最少访问的元素。当调用get()方法访问缓存对象时,就会调用LinkedHashMap的get()方法获得对应集合元素,同时会更新该元素到队尾。

主要线程池?
public Glide build(@NonNull Context context) {
if (sourceExecutor == null) {
    sourceExecutor = GlideExecutor.newSourceExecutor();//创建网络加载线程池对象
}
if (diskCacheExecutor == null) {
    diskCacheExecutor = GlideExecutor.newDiskCacheExecutor();//创建磁盘加载线程池对象
}

if (animationExecutor == null) {
    animationExecutor = GlideExecutor.newAnimationExecutor();//创建动画加载线程池对象
}}

1.3. Gilde缓存机制?
Glide缓存分为内存缓存和磁盘缓存,其中内存缓存是由弱引用+LruCache组成。
• 取的顺序是:弱引用、LruCache、磁盘
• 存的顺序是:磁盘、弱引用、LruCache

1、弱引用
弱引用是由这样一个HashMap维护,key是缓存的key,这个key由图片url、width、height等10来个参数组成;value是图片资源对象的弱引用形式。
Map<Key, ResourceWeakReference> activeEngineResources = new HashMap<>();
2、LruCache
LruCache是由一个LinkedHashMap维护,根据Lru算法来管理图片。大致的原理是利用LinkHashMap链表的特性,把最近使用过的文件插入到列表头部,没使用的图片放在尾部;然后当图片大小到达预先设置的一个阀值的时候 ,按算法删除列表尾部的部分数据。
#LruCache
Map<T, Y> cache = new LinkedHashMap<>(100, 0.75f, true);

磁盘缓存原理(DiskLruCache)
• DiskCacheStrategy.DATA: 只缓存原始图片;
• DiskCacheStrategy.RESOURCE:只缓存转换过后的图片;
• DiskCacheStrategy.ALL:既缓存原始图片,也缓存转换过后的图片;对于远程图片,缓存 DATA和 RESOURCE;对于本地图片,只缓存 RESOURCE;
• DiskCacheStrategy.NONE:不缓存任何内容;
• DiskCacheStrategy.AUTOMATIC:默认策略,尝试对本地和远程图片使用最佳的策略。当下载网络图片时,使用DATA(原因很简单,对本地图片的处理可比网络要容易得多);对于本地图片,使用RESOURCE。

1.4 Glide内存缓存如何控制大小?

blog.csdn.net/github_3713…

一种是Resource缓存,一类是Bitmap缓存。

1)Resource缓存: 图片从网络加载,将图片缓存到本地,当需要再次使用时,直接从缓存中取出而无需再次请求网络。

Glide在缓存Resource使用三层缓存,包括:

一级缓存:缓存被回收的资源,使用LRU算法(Least Frequently Used,最近最少使用算法)。当需要再次使用到被回收的资源,直接从内存返回。
二级缓存:使用弱引用缓存正在使用的资源。当系统执行gc操作时,会回收没有强引用的资源。使用弱引用缓存资源,既可以缓存正在使用的强引用资源,也不阻碍系统需要回收无引用资源。
三级缓存:磁盘缓存。网络图片下载成功后将以文件的形式缓存到磁盘中。

2)Bitmap缓存:  通过Bitmap压缩质量参数,Glide默认使用RGB_565,比系统默认使用的ARGB_8888节省一半的资源,但RGB_565无法显示透明度。

Bitmap缓存算法:

在Glide中,使用BitmapPool来缓存Bitmap, 使用的也是LRU算法。
当需要使用Bitmap时,从Bitmap的池子中取出合适的Bitmap,若取不到合适的,则再新创建。
当Bitmap使用完后,不直接调用Bitmap.recycler()回收,而是放入Bitmap的池子。

1.5、Glide使用什么缓存?

   www.jianshu.com/p/62b7f990e…

BitmapPool 大小通过 MemorySizeCalculator 设置;
使用 LRU 算法维护 BitmapPool ;
Glide 会根据 Bitmap 的大小与 Config 生成一个 Key;Key 也有自己对应的对象池,使用 Queue 实现;
数据最终存储在 GroupedLinkedMap 中;GroupedLinkedMap 使用哈希表、循环链表、List 来存储数据。 


三.常见面试问题?
1.1 介绍下Glide的缓存?
Glide的缓存机制,主要分为2种缓存,一种是内存缓存,一种是磁盘缓存。
内存缓存原因:防止应用重复将图片读入到内存,造成内存资源浪费。

磁盘缓存原因:防止应用重复的从网络或者其他地方下载和读取数据,而它内部实际是有三级缓存机制。两种缓存结合,才构成了Glide极佳缓存效果,而它的缓存策略采用的LruCache 算法缓存。

三级缓存(Lru算法缓存、弱引用缓存、磁盘缓存) ?
当想要加载某张图片时,先去LruCache中寻找图片,如果LruCache中有,则直接取出来使用,如果LruCache中没有,则去WeakReference中寻找,如果WeakReference中有,则从WeakReference中取出图片使用,同时将图片重新放回到LruCache中,如果WeakReference中也没有图片,则去文件系统中寻找,如果有则取出来使用,同时将图片添加到LruCache中,如果没有,则连接网络从网上下载图片。图片下载完成后,将图片保存到文件系统中,然后放到LruCache中。

LRUCache 原理?
把最近使用的对象用强引用存储在 LinkedHashMap 中,当缓存满时,把最近最少使用的对象从内存中移除,并提供 get/put 方法完成缓存的获取和添加LruCache 是线程安全的,因为使用了 synchronized 关键字。LinkHashMap继承HashMap,在 HashMap的基础上,新增了双向链表结构,每次访问数据的时候,会更新被访问的数据的链表指针,具体就是先在链表中删除该节点,然后添加到链表头header之前,这样就保证了链表头header节点之前的数据都是最近访问的。

简单介绍LruCache?
最近最少使用算法,设定一个缓存大小,当缓存达到这个大小之后,会将最老的数据移除,避免图片占用内存过大导致OOM。
LruCache 内部用LinkHashMap存取数据,在双向链表保证数据新旧顺序的前提下,设置一个最大内存,往里面put数据的时候,当数据达到最大内存的时候,将最老的数据移除掉,保证内存不超过设定的最大值。
关于LinkedHashMap了解多少?
LinkHashMap继承HashMap,在 HashMap的基础上,新增了双向链表结构,每次访问数据的时候,会更新被访问的数据的链表指针,具体就是先在链表中删除该节点,然后添加到链表头header之前,这样就保证了链表头header节点之前的数据都是最近访问的(从链表中删除并不是真的删除数据,只是移动链表指针,数据本身在map中的位置是不变的)。

具体Glide的三级缓存原理?
读取一张图片的时候,获取顺序:Lru算法缓存-》弱引用缓存-》磁盘缓存(如果设置了的话)。
当加载图片时,先去LruCache中寻找图片,如果LruCache中有,则直接取出来使用,并将该图片放入WeakReference中,如果LruCache中没有,则去WeakReference中寻找,如果WeakReference中有,则从WeakReference中取出图片使用,如果WeakReference中也没有图片,则从磁盘缓存/网络中加载图片。


将图片缓存的时候,写入顺序:弱引用缓存-》Lru算法缓存-》磁盘缓存中。
当图片不存在的时候,先从网络下载图片,然后将图片存入弱引用中,glide会采用一个acquired(int)变量用来记录图片被引用的次数,
当acquired变量大于0的时候,说明图片正在使用中,也就是将图片放到弱引用缓存当中;
如果acquired变量等于0了,说明图片已经不再被使用了,那么此时会调用方法来释放资源,首先会将缓存图片从弱引用中移除,然后再将它put到LruResourceCache当中。这样也就实现了正在使用中的图片使用弱引用来进行缓存,不在使用中的图片使用LruCache来进行缓存的功能

1.2  Glide加载一个一兆的图片(100 * 100),是否会压缩后再加载,放到一个300 * 300的view上会怎样,800*800呢,图片会很模糊,怎么处理?
当我们调整imageview的大小时,Picasso会不管imageview大小是什么,总是直接缓存整张图片,而Glide就不一样,它会为每个不同尺寸的Imageview缓存一张图片,也就是说不管你的这张图片有没有加载过,只要imageview的尺寸不一样,那么Glide就会重新加载一次,这时候,它会在加载的imageview之前从网络上重新下载,然后再缓存。Glide 缓存的key 的生成条件之一就是 控件的宽高。

如果在一个页面中使用Glide加载了一张图片,图片正在获取中,如果突然关闭页面,这个页面会造成内存泄漏吗?怎么解决
因为Glide 在加载资源的时候,如果是在 Activity、Fragment有生命周期的组件上进行的话,会创建一个透明的RequestManagerFragment 加入到FragmentManager 之中,感知生命周期,当Activity、Fragment 等组件进入不可见,或者已经销毁时候,Glide会停止加载资源。
但是如果,是在非生命周期的组件上进行时,会采用Application 的生命周期贯穿整个应用,所以 applicationManager只有在应用程序关闭的时候终止加载。

1.4 自定义图片加载框架思路?
• 异步加载:线程池
• 切换线程:Handler
• 缓存:LruCache、DiskLruCache
• 防止OOM:软引用、LruCache、图片压缩、Bitmap像素存储位置
• 内存泄露:注意ImageView的正确引用,生命周期管理
• 列表滑动加载的问题:加载错乱、队满任务过多问题

自己去实现图片库,怎么做?

图片的同步加载
图片的异步加载
图片压缩
内存缓存
磁盘缓存
网络拉取

1.5 如何设计一个大图加载框架?
概括来说,图片加载包含封装,解析,下载,解码,变换,缓存,显示等操作。

1.6 高清加载大图?
加载图片一般为了尽可能避免OOM都会按照如下做法:
1. 对于图片显示:根据需要显示图片控件的大小对图片进行压缩显示。
2. 如果图片数量非常多:则会使用LruCache等缓存机制,将所有图片占据的内容维持在一个范围内。
3. 但是单个图片非常巨大,并且还不允许压缩。比如世界地图、清明上河图、微博长图等 ,以上2种方案不适用。
解决方案:局部加载(BitmapRegionDecoder) 

posted on 2020-05-05 13:23  左手指月  阅读(433)  评论(0编辑  收藏  举报