glide

子线程 : 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 内存缓存)

正在使用的图片由内存缓存移动到活跃缓存,同时引用计数+1。当为0时候移动到内存缓存。

三个工作场景
从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、网络断开放入等待队列

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值