子线程 : Application作用域
主线程 :非Application作用域 生成空白的Fragment
图解如下:
1、glide 单例
2、FragmentManager 保存空白的fragment,通过tag获取。
3、LifecycleListener 接口,onStart()/onStop/onDestroy
4、Lifecycle
方法有addListener(LifecycleListener listener)、removeListener(LifecycleListener listener)
接口子类有ActivityFragmentLifecycle 和 ApplicationLifecycle
内部维护Set<LifecycleListener>
5、SupportRequestManagerFragment 空白的fragment构造方法中初始化Lifecycle
6、RequestManagerRetriever 在glide构造方法中初始化 单例,
主要把初始化好的SupportRequestManagerFragment commitAllowingStateLoss()。然后返回当前activity的RequestManager
7、RequestManager 创建成功后设置到空白的fragment中。在自己的构造方法中接收SupportRequestManagerFragment 传递过来的Lifecycle,并执行lifecycle.addListener(this)把自己添加到Set<LifecycleListener>集合中
with的时候执行5、7、6。fragment start的时候执行 5、4、7
第六步的详细步骤如下:
1、从FragmentManager根据tag查询fragment-没有
2、根据Map<FragmentManager, SupportRequestManagerFragment>查询fragment -没有
3、创建fragment,同时设置到Map中
4、commint提交
5、发送handler 移除Map中的fragment
我理解的一个 app 中只有一个RequestManagerRetriever
一个 activity 只有一个fragment、RequestManager、ActivityFragmentLifecycle
上面介绍完了,在看一下时序图
glide整体的流程
glide图片加载流程
其他:
构建Glide对象
1.创建加载引擎Engine对象(包括缓存配置等);
2.构建registry,注册了众多加载器与编解码器;
3.构建RequestManagerRetriever对象。
构建RequestManager对象
1.如果在子线程中加载图片或with中的参数为Application类型,则Glide图片加载的生命周期与Application生命周期绑定;
2.否则,Glide图片加载的生命周期与Activity或Fragment的生命周期绑定。
aplication中加载 会持有imageview。如果图片一直加载。导致activity无法释放
aplication使用场景:预加载
一些类的讲解
requestManager 管理一个activity所有请求。
decodejob 是一个runnable 耗时操作-文件
enqinejob 是一个线程池 内存缓存 用map集合保存
modelLoader 是根据load(url) 参数类型找到对应的类进行加载
ResourceDecoder 解码数据为bitmap
Transformation 转成成资源缓存
四种缓存
内存:
1、活动缓存:弱引用集合
2、内存缓存:LRU算法
文件:LRU算法
3、资源缓存:经过了变换的图片
4、数据缓存:原图数据缓存( jakeWharton/DiskLruCache 内存缓存)
三个工作场景
从Reources缓存加载 (变换后的图片缓存)
从Data缓存加载 (原始图片缓存)
从图片源加载 (http网络图片加载)
LruBitmapPool 复用池
当内存缓存回收后,并不会马上调用recycle(),而是先放入到复用池。等下次bitmap在初始化的时候会去复用池查找(现图片<=复用图片大小 && 最高不能超过现图8倍)
把bitpmap设置可复用代码
BitmapFactory.Options options = new BitmapFactory.Options();
options.inBitmap = oldBitmap; //复用老图片内存
options.inMutable = true; //新图片也能被复用
Bitmap result = BitmapFactory.decodeStream(inputStream, null, options);
图解如下:
从复用池获取。 利用TreeMap 可以得到最接近的内存值。可以参考这个地址
内存缓存怎么放入复用池
@Test
public void addition_isCorrect() {
Bitmap bitmap = new Bitmap();
MyBitmap myBitmap = new MyBitmap();
myBitmap.bitmap = bitmap;
//使用弱引用队列监听
final ReferenceQueue<MyBitmap> queue = new ReferenceQueue<>();
MyRef weakReference = new MyRef(myBitmap, queue);
new Thread() {
@Override
public void run() {
try {
// 让bitmap 又加入回 内存缓存中!remove()是一个等待方法。
//只有当被监听的对象回收了,才会被唤醒
MyRef remove = (MyRef) queue.remove();
// 获得MyBitmap被回收的通知,把Bitmap放回内存缓存
Bitmap bitmap1 = remove.ref;
System.out.println("remove:" + bitmap1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
//让mybitmap被回收,Bitmap不会被回收,因为在MyRef里还有强引用
myBitmap = null;
System.gc();
}
//当MyBitmap 设置为null的时候bitmap的引用被MyRef类里面的ref所强引用。
//所以当MyBitmap被回收,Bitmap对象不会被回收。
static class MyBitmap {
Bitmap bitmap;
}
static class MyRef extends WeakReference<MyBitmap> {
public final Bitmap ref;
public MyRef(MyBitmap referent, ReferenceQueue<? super MyBitmap> q) {
super(referent, q);
this.ref = referent.bitmap;
}
}
默认缓存策略
AuTOMATIC默认缓存网络原始图片、本地修改后的图片
大图加载策略
使用bitmpaRegionDecoder 加载指定的区域
设计模式
单例、builder、工厂、代理、装饰
面试题
1、能不能在线程中使用Glide,有没有什么问题?
•Glide.with.load能在子线程调用,into方法不允许。into中会首先查找内存缓存,如果内存缓存存在需要显示的图片则直接设置显示,这时只能在主线程。实际上into方法一开始就判断了当前线程非主线程则抛出异常;
•不建议传递Activity,因为当处于子线程,这时候Glide.with中会获取ApplicationContext来获取RequestManager,导致此RM管理的加载请求无法管理页面生命周期。
2、glide为什么不单独用内存缓存?
内存缓存使用的LRU算法。如果图片缓存数量已超过最大设置的数量,这个时候最少使用的图片将会被移除掉(暂未释放),这时候glide将无法管理当前图片的生命周期。如果移除的同时也释放,这时候图片正在使用,会抛出异常。
3、glide优先级加载实现
线程池使用了优先级队列(PriorityBlockingQueue), DecodeJob实现了Comparalbe接口,通过Priority参数可对比排序
4、解释modeLoader
modeLoader 加载图片的解析器或者模型加载器,通过url类型能定位到到使用什么类型的加载器来转换解析
5、从网络加载一个巨图,需要注意什么?
1、将BitmapFactory.Options的inJustDecodeBounds参数设为true并加载图片;
2、从BitmapFactory.Options中取出图片的原始宽高信息:outWidth和outHeight;
3、根据目标View的所需大小计算出inSampleSize( inSampleSize 能被2整除);
4、将BitmapFactory.Options的inJustDecodeBounds参数设为false,然后重新加载图片。
代码如下:
BitmapFactory.Options options = new BitmapFactory.Options();
//只加载大小
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile("xx", options);
options.inJustDecodeBounds = false;
options.inSampleSize = x;
BitmapFactory.decodeFile("xx", options);
解码图片注意事项
以PNG为例,PNG图片的数据中IHDR后为图像宽、高,若以流的形式读取此段数据,则流中数据已经被读走,不是完整的图像数据流,再次进行图片解析会由于缺失数据而解析失败。
解决方案
其他说明:
inSampleSize=5 会往下缩放2,4,8.... 为(4)
apt技术一方面是为了扩展图片加载接口。比如想加载svg图片
glide中会有以下监听:
1、onTrimMemory 内存不够监听
2、网络断开放入等待队列