with-空白fragment
Glide中with函数有很多的重载方法,可以传入Context,Activity,FragmentActivity,v4.Fragment,android.app.Fragment,View等等,而这些参数的类型决定了Glide的作用域。这些作用域可以分为Application作用域(从应用启动到应用销毁)和非Application作用域(从页面启动到页面销毁),针对非Application作用域,Glide会在with函数中创建出一个空白的fragment和当前页面(如Activity)绑定,这样以来就可以监听到当前页面的启动和销毁的一系列生命周期(Glide主要监听onStart onStop onDestroy),从而做到在页面启动之后开启图片的加载,在页面退出之后暂停图片的加载,以及对活动缓存的一些列操作等等。
精确到代码层面,Glide在with函数调用的时候会有两个关键的类被创建出来,一个是上面提到的Fragment(如RequestManagerFragment),另一个就是ReqeustManager,专门负责生命周期的管理。在ReqeustManager创建的时候,会持有RequestManagerFragment中的lifecycle对象的引用,并将当前ReqeustManager注册到RequestManagerFragment lifecycle的集合中,而RequestManagerFragment监听到生命周期的回调之后就回通过遍历lifecycle集合通知到每一个ReqeustManager,ReqeustManager就可以管理到Glide加载的生命周期了。
load
load函数的逻辑很简单,他也有多种重载方法,但是不管是哪种方法,最终都是通过RequestBuilder去load,而RequestBuilder中只是保存了资源的地址而已
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
into
into方法的核心可以说是在com.bumptech.glide.load.engine.Engine这个类中
public <R> LoadStatus load(...){
...
//拿到缓存或者请求的 key
EngineKey key = keyFactory.buildKey(model, signature, width, height, transformations,
resourceClass, transcodeClass, options);
//根据 key 拿到活动缓存中的资源
EngineResource<?> active = loadFromActiveResources(key, isMemoryCacheable);
if (active != null) {
cb.onResourceReady(active, DataSource.MEMORY_CACHE);
}
return null;
}
//活动缓存没有,就去尝试从 LruResourceCache 中找寻
EngineResource<?> cached = loadFromCache(key, isMemoryCacheable);
if (cached != null) {
cb.onResourceReady(cached, DataSource.MEMORY_CACHE);
return null;
}
//活动缓存 跟内存缓存都没有找到,看看请求任务是否已经开始执行了
EngineJob<?> current = jobs.get(key, onlyRetrieveFromCache);
if (current != null) {
current.addCallback(cb);
return new LoadStatus(cb, current);
}
//构建新的请求任务
EngineJob<R> engineJob =...
DecodeJob<R> decodeJob =...
//保存,和上边相呼应
jobs.put(key, engineJob);
engineJob.addCallback(cb);
engineJob.start(decodeJob);
return new LoadStatus(cb, engineJob);
}
Glide相较于一般的图片框架三级缓存的逻辑,他的缓存层多了一层活动缓存的概念,所以他可以说是具有四级缓存,活动缓存,内存缓存,磁盘缓存和网络缓存。
这里重点提一下活动缓存的概念。活动缓存是为了解决内存缓存的不确定性而生的,我们知道内存缓存使用LRU算法维持缓存的容量,所以内存缓存的缓存资源是不断的动态调整的,这样就存在一个问题,在显示图片的时候,当前页面中,某一图片已经加载过网络资源,但是被清理了,不得不再去磁盘或者网络上获取,一定程度上这是一种低效的行为。所以Glide创建了活动缓存,活动缓存的生命周期只针对当前页面,他通过弱引用来维持了一个容量无上限的集合,来降低缓存被清理的几率,但是又不会导致内存占用的不断增大。当前页面中的缓存都会被添加到活动缓存集合,并且从内存缓存集合移除,当页面退出时又会把缓存从活动缓存移除,添加到内存缓存中,二者是互斥的一个关系。
相关面试题汇总
1.Glide加载一个一兆的图片(100100),是否会压缩后再加载,放到一个200200的view上会怎样,1000*1000呢,图片会很模糊,怎么处理?
Glide从来都不会直接将图片的完整尺寸全部加载到内存中,而是用多少加载多少。Glide会自动判断ImageView的大小,然后只将这么大的图片像素加载到内存当中。当我们调整imageview的大小时,Glide会为每个不同尺寸的Imageview分别缓存一张图片,举个例子,如果一个页面的imageview是200200像素,而另一个页面中的imageview是100100像素,虽然两个imageView用的是同一张图片,但是Glide仍需要下载两次图片,并且缓存两张图片。
2.Glide VS Picasso
1.Glide支持Gif, Picasso不支持
2.Picasso的默认加载图片的格式是 ARGB_8888(32位图,带透明度,每个像素占4个字节),Glide是RGB_565(16位图,不带透明度,每个像素占2个字节),是Picasso的内存占用的一半
加载一张4000 * 2000的图片,
Picasso需要占用的内存为: 32MB
4000 * 2000 * 4 / 1024 / 1024 = 30 (MB)
Glide需要占用的内存为: 16MB
4000 * 2000 * 2 / 1024 / 1024 = 15 (MB)
3.Glide支持内存分级缓存:正在使用的图片,弱引用缓存;已使用过的图片LruCache缓存,Glide会为不同的ImageView尺寸缓存不同尺寸的图片
4.Glide会按照ImageView的大小来缓存图片,而Picasso不管imageview大小是什么,总是直接缓存整张图片。比如原图1M,加载到一个10*10的ImageView上,Glide会缓存压缩后的图片,Picasso则会直接缓存这个1M的图片
3.Glide VS fresco
1.fresco 在低版本Android(4.x and lower)上使用native 内存规避掉了 OutOfMemoryError 问题,但是高版本仍然是java内存,这种情况和Glide差不多
2.fresco 推荐的是用他提供的 SimpleDraweeView . 这意味着我们的迁移成本会很高,要改布局文件,其次还必须给定大小(或者比例);Glide纯代码加载,迁移起来更灵活
3.Glide支持各种 BitmapTransformation,比如圆形,圆角等,fresco不支持
4.Glide缓存原理
相较于传统图片加载框架的三级缓存来说,Glide可以说具备四级缓存,1.活动缓存(弱引用缓存),2.LruCache缓存,3.磁盘缓存,4.网络缓存。
活动缓存是当前正在使用的缓存,会通过弱引用包裹,并且没有内存上限设置,他和LruCache缓存是互斥的,也就是当前如果在活动缓存中保存了一个图片,那么在LruCache中就会移除,活动缓存中的缓存来自LruCache,当活动缓存中的缓存对象不再有引用(类似引用计数法)时,就会将其从活动缓存删除,加入到L ruCache缓存,其他地方同其他框架相差无几
网友评论