美文网首页
Glide源码小记

Glide源码小记

作者: 魔焰之 | 来源:发表于2019-03-26 23:59 被阅读0次

    Glide 3.7源码阅读要点:

    角色介绍:

    Glide:对外暴露的统一接口,静态单利,内部成员众多,主要涉及缓存管理和请求管理
    Request:抽象的请求接口,定义了一起加载操作相关的生命周期接口
    RequestManager:请求管理器,同时是一个生命周期的监听者,其具备网络状态获取,请求管理(委托给RequestTracker实现),生命周期回调的能力
    RequestTracker:请求跟踪器,只负责Request的保存和相关生命周期的分发
    RequestManagerRetriever: 请求管理器的管理者(请求管理的猎犬),金静态单利,通过上下文信息返回不同的RequestManager
    ModelLoader: model加载器,这里的model其实是对应一种输入类型,比如我想加载一个url对应的图片,这个string或者uri对应的类型就是一种model,该接口返回DataFetcher对象,真正的资源获取操作操作都在DataFetcher里
    DataFetcher:处理数据获取的操作,比如从网上加载或者从本地目录,一般输出是InputStream
    Encoder:数据的写入接口,比如将DataFetcher输出的InputStream写入到某个本地文件(StreamEncoder),一般在数据缓存时会用到这个接口
    ResourceDecoder:这个接口对应原始数据类型转换为ViewTarget能使用的操作,比如将InputStream转换为Resource<Bitmap>

    1. 初始化流程

    Glide对象创建
    Glide对象的创建是延迟创建,单利对象,采用建造者模式的方式,此外还支持使用方参与其构建过程,我们可以在AndroidManifest文件中的meta-data中配置自定义的GlideModule类来参与。
    glide对象
    1.内部使用了两个线程池,都是使用的PriorityBlockingQueue阻塞队列和默认的拒绝策略
    2.内存缓存也分为了两部分:bitmap缓存和其他内存缓存,其大小比列是4:2(你可以理解成大小分别为4张和2两张截图的大小),这里使用了MemorySizeCalculator这个对象来计算实际大小,该计算器会根据sdk版本和app所申请的实际内存大小来动态计算(实际就是sdk版本和activityManager.isLowRamDevice这个api)
    3.diskCacheFactory是一个磁盘缓存工厂类,使用最近最少使用的缓存策略,默认大小是250mb,默认路径为/data/data/<application package>/cache/image_manager_disk_cache
    4.engine就是真正负责处理资源的类,其负责管理资源加载任务,回收资源等工作
    Glide构造函数
    在Glide的构造函数中,主要关注一下成员:
    1.dataLoadProviderRegistry是一个数据加载器的提供者(这里的数据针对的是加载到内存的数据),负责提供不同数据类型数据加载器(不同数据类型之间转码或者数据压缩的工作),比如压缩bitmap等
    2.loaderFactory是一个数据加载器工厂,负责提供各种数据加载器(ModelLoader实现者),这里的数据针对的是从磁盘或者在线下载的数据,比如给定一个url,输出一个inputStream。可以看到默认注册了很多的加载器
    3.transcoderRegistry中注册了资源转换的转换器,比如将bitmap转换成drawable类型等
    1. 简单流程
    Glide.with(applicationContext).load(url).diskCacheStrategy(DiskCacheStrategy.ALL).into(imageView);
    

    上述是我们使用Glide加载一个网络图片的最简单的使用案例,接下来看一下这个最简单的流程源码实现:
    1.Glide.with方法由多个重载方法实现,最终都是调用到RequestManagerRetriever的get方法,该方法会根据上下文类型返回不同的RequestManager,这里我使用Application,则会返回包含ApplicationLifecycle的RequestManager实例


    RequestManagerRetriever.get

    2.RequestManager.load方法也是一个重载的方法,不同的参数类型对应不同的资源加载,我这里是一个String类型的url.这里直接进入fromString方法,最终会转到loadGeneric方法上


    RequestManager.load
    loadGeneric
    loadGeneric方法中主要是获取了相关的modelLoader,最后再返回一个DrawableTypeRequest对象,这里streamModelLoader的实际类型是StreamStringLoader(其真正使用的是HttpUrlGlideUrlLoader类型对象,该对象可以返回HttpUrlFetcher实例,负责做真正的数据获取工作),fileDescriptorModelLoader的实际类型是FileDescriptorStringLoader。
    load

    返回DrawableTypeRequest之后开始初始化相关的成员参数,load方法的实现如上,这里的ModelType就是我们之前的String类型,model就是url


    diskCacheStrategy()
    上述方法是缓存模式的设置,glide中支持四种:
    缓存模式
    DiskCacheStrategy.NONE:表示不缓存
    DiskCacheStrategy.SOURCE:表示仅缓存源资源,这里的源资源就是从从网上或者文件中加载到的原始InputStream资源
    DiskCacheStrategy.RESULT:表示仅缓存处理(比如资源压缩/尺寸裁剪)之后的资源,不保留原始资源
    DiskCacheStrategy.ALL:表示既缓存原始资源,又缓存处理之后的资源
    接下来就是into方法的流程了,如图:
    GenericRequestBuilder中的into方法
    可以看到这里先检验了是否在主线程,标志着该方法只能在主线程调用,之后会检查目标View是否为空,之后会检查该ImageView是否设置了ScaleType,如果设置了,则需要处理图片,我这里都没有设置,最后会调用into的重载方法,传入的参数是GlideDrawableImageViewTarget类型的对象(可以从ImageViewTargetFactory这个工厂类看到具体的类型匹配)
    into

    上图是into的一个重载方法,传进来的参数target就是GlideDrawableImageViewTarget类型的对象,这里直接看target.getRequest,该方法返回一个Request实例,可以看到其实现就是调用的View.getTag或者View.getTag(tagId);也就是说使用Glide加载图片的View是不能自己调用setTag方法的,


    getRequest方法的实现
    回到into方法内部,原则上来讲,如果是第一次作为ViewTarget,previous变量为空,如果不是第一次,则会返回之前绑定的request(GenericRequest类型)实例,所以这里先回收了之前的request,之后开始创建本次Request实例并设置相关的成员变量,Request对象的创建是用了对象缓存池,其数据结构是ArrayDeque,之后将request对象和ViewTarget绑定关系,然后将request对象给requestTracker(专职的request生命周期跟踪者),该对象会缓存请求,并调用请求对象的begin方法,开始请求流程
    request.begin
    begin这个方法先改变request的状态为WAITING_FOR_SIZE,之后检查宽高是否可用,我没有设置过,所以会调用target.getSize来计算宽高,实际上就是获取View的宽高,获取成功之后会调用onSizeReady方法,之后会给targetView设置一个默认加载前的图片
    尺寸准备好了
    onsizeReady方法先检查并设置了请求的status,之后获取了相关的modelLoader,这里是一个ImageVideoModelLoader实例,之后通过modelLoader获取了一个dataFetcher,这是一个ImageVideoFetcher实例,其中之前的streamLoader(StreamUriLoader类型)和fileDescriptorLoader,实际上最后从网络上加载的操作是委托给了HttpUrlFetcher。之后是获取了资源转换器(GifBitmapWrapperDrawableTranscoder类型),开始进入engine的加载数据环节
    engine.load
    engine是资源获取的中枢控制器,这里的load方法做了如下事情:
    1.针对资源生成了唯一的Key,后续从内存读取缓存资源的key值
    2.首先从内存中加载缓存的资源,这里的内存缓存就是我们之前提到的memoryCache(MemoryCache接口的实现者,这里的是LruResourceCache实例),如果命中内存缓存,就调用onRourceReady告诉监听者,这里的监听者就是之前的request对象,这里需要说明一下,当命中缓存后,engine会将命中的资源数据存储到一个hashmap中,表示该资源正在被使用。也就是说glide的内存缓存大小不等于其计算的bitmap池和memoryCache的和
    3.如果没有命中缓存,则会尝试从正在使用的hashmap中再去查找一下
    4.如果还是没有命中,则先检测是否该资源正在加载的过程中,若是则等他其加载之后的回调,结束本次加载,避免重复
    5.如果当前需要的资源没有加载过,则新建EngineJob和相关的DecodeJob,并包装到EngineRunnable中,开始从磁盘或者网络中进行资源加载,从这里开始,后续的操作都在线程池里了,EngineRunnable对象的run方法会直接调用decode方法:
    加载数据的入口方法
    decode方法首先会判断是否从本地缓存文件中去获取,默认第一次都是先尝试加载本地缓存文件,如果本地缓存文件没有,则会去下载,相关方法如下:
    获取本地缓存文件
    加载本地缓存的经过处理的数据文件
    加载文件
    这里的diskCacheProvider是InternalCacheDiskCacheFactory类型的对象,这里首先会获取缓存目录下指定的结果缓存文件(即非原始数据的缓存文件),如果存在则执行decode操作,可以理解为资源类型的转换操作。如果没有获取到非原始的缓存,则会尝试获取原始数据缓存文件;如果获取成功,则本次结束
    接着看下从网络获取的流程:
    从网络获取
    decodeSource方法是入口函数,首先使用fetcher去加载数据,这里实际就是上文提到的HttpUrlFetcher对象,其loadData方法的本质就是使用HttpURLConnection去获取inputStream,decodeSource获取到inputStream之后,调用decodeFromSourceData方法,这个方法会判断是否需要缓存原始数据流,如果需要,则会缓存到本地文件(cacheAndDecodeSourceData方法),之后再从本地将数据加载返回。如果不需要,则直接进行数据的类型转换操作(decode),并返回相关数据给engineJob(调用onResourceReady),然后engineJob发消息给主线程,通知进行ui层面的数据填充。这样一个完整的流程就走完了。

    相关文章

      网友评论

          本文标题:Glide源码小记

          本文链接:https://www.haomeiwen.com/subject/ganovqtx.html