在这一周的时间内,事情不是太多,简单的阅读了下Glide 3.6.1的源码,对于其整个调用流程有了一定的了解,希望通过本篇将其总结下来,一来加深印象,二来以后可以反复修改。主要想通过时序图分享一下Glide的调用流程以及其中比较关键的生命周期管理和数据处理流程。
在整个分析的过程中都基于
Glide.with(context).load(“”).asBitmap().into(imageView)
这一条简单的Glide的使用,了解背后的机制
以下是在在这个上述调用中的整个流程的时序图
分析流程主要分为四部分:
1、初始化:加载库中已经注册的和用户在Manifest文件中注册的数据、建立生命周期的回调以及资源回调
2、Request创建
3、Request调度:解析缓存资源
4、资源回调:资源解析完毕后,将其加载到与之对应的Target中
初始化过程包括各种数据的预加载,以及生命周期的绑定和各种回调接口的设置。
1、其中为了方便使用,因为DataLoadProvider关联三个类型、ModuleLoader通DataLoadProvinderRegistry建立 dataClass 、sourceClass、DataLoadProvinder之间的映射关系通过TranscoderRegistry 建立 decodedClass 与transcoderClass 之间的管理,方便之后的使用。不过,存在一个小问题是,在初始化的时候注册了太多与当前项目无关的数据,不过为了通用,这个是不可避免的了。
2、通过无界面的Fragment将当前Context 下所对应的LifeCycleListener对应的生命周期与当前Context的生命周期绑定在一起 ,从而可以动态调整request、网络状态监听等
(时序图比较大,看的不是很清楚)
Glide
框架的入口类,提供了各种静态方法来创建request管理engine 、BitmapPool、DiskCacke、MemoryCacheGlideBuilder 给Glide设置一些默认配置,从而更方便创建Glide,可以认为是Builder Pattern,将构造函数分解为:先设置属性,然后创建
GlideModule
允许Glide使用GlideBuilder延迟加载一些配置选项和ModelLoader的注册,当编写一个Module之后,需要在AndroidManefist.xml中meda-data配置,然后使用的时候通过 ManifestParser解析反射使用
注意:1、所有的实现module必须是Public,拥有一个空的构造函数,以便Glide通过反射来懒加载
2、GlideModule的调用注册是随机的,因此在创建多个GlideModule时,要注意不同Module之间的setting不要产生冲突。如果应用依赖已经有冲突的libraries,应该考虑将在单一的Application Module中注册。
DataloadProviderRegistry
考虑到DataLoadProvider 关联两个指定的Data、Resource类型,所以在应用初始化的时候,就将使用到的DataLoadProvider与之相关联的两个类绑定在一起(注册),然后使用的时候根据需要转换的两个类型来获取对应的DataLoadProvider来decode(解析) 、encode(缓存)
TranscoderRegistry
与DataLoadProviderRegistry 类似,只不过注册的是 从A转换到B,与之使用到的资源解析类型三个类之间的关系
GenericLoaderFactory
ManifestParser
解析在AndroidManifest中使用到的GlideModule然后反射使用
RequestManager
管理、启动requests,可使用Activity、Fragment、 Connectivity 等生命周期方法来管理和启动请求,主要实现方式是使用Fragment 作为媒介,将自定义的LifeCycle接口与这些生命周期管理绑定在一起(后续会详细介绍)
1、任务调度,根据生命周期启动、暂停、终止系统中已有的任务
2、为RequestManagerFragment设置生命周期监听:任务监听、网络添加、图片动画监听(这个监听要延迟到Target创建成功才会创建,所以就要把lificycle传递)等
注意:因为RequestManager是与Activity、Fragment等Context绑定在一起来管理request的,所以要使用尽量小的Context,避免使用Application等全局上下文,如果使用全局比较大的上下文,与其相关的Options会一直保存在内存中,所以可能 leak memory
RequestManagerTreeNode
提供了可以访问当前上下文中所有的RequestManager,也就是说基于Context层次结构建立了RequestManager的层次结构,而上下文的层次结构是在Activity / Fragment中嵌套的。不过,注意,如果当前上下文是Application Context ,只能访问当前上下文的RequestManager. 总而言之就是更方便的管理所有的RequestManager 。
RequestManagerRetriever
可用来创建RequestManager或者从Activity和Fragment 中检索已经存在的RequestManager来重用
SupportRequestManagerFragment
和RequestManagerFragment一样,都是一种Fragment,,只不过是没有任何界面信息,总关键的时可以用来管理RequestManager 的start、staop、管理request。更广泛的说法是可以储存实现了LifecycleListener 接口的对象(比如Fragment、ConnectivityMonitor),然后在Fragment 的生命周期方法中回调LifeCycle,从而将自定义的LifeCycle生命周期回调与当前Fragment所在的父Activity/Fragment 绑定在一起。
ConnectivityMonitor
网络状态的监听接口,实现了LifecycleListener ,与Activity/Fragment 生命周期绑定在一起。具体实现DefaultConnectivityMonitor 以及NullConnectivityMonitor ,其中前者是一个网络监听的具体实现,后者是一个空实现,类似于Null Object Pattern ,可以避免空指针异常
ActivityFragmentLifecycle
一个LifeCycle接口的具体实现,可用来在在Fragment 的生命周期方法中跟踪、通知LifecycleListener。
当RequestBuilder创建好之后,就可以创建request,来发起请求,在Into这个方法中,首先创建了 ViewTarget来封装View,从而可以在其周围添加相关的生命周期回调方法,可以在图片请求到时进行设置,然后就是创建Request,并将request相关信息保存在 ViewTarget,从而达到重用的目的。当Request创建好之后,就可以通过RequestTarcker来调度发起请求,当获取请求是则进入下一步
Engine
Responsible for starting loads and managing active and cached resources.
Start load
实现了各个资源回调,用于管理磁盘、内存中的缓存资源
主要方法:
Load():
Starts a load for the given arguments .必须在主线程中调用。
调用流程主要分为两部分:
1、获取缓存的EngineResource:分别从缓存、内存活态中获取
2、EngineJob调度新的任务:
从jobs池中获取
创建新的EngineJob
详细操作流程如下所示:
EngineJob
介于Engine. EngineRunnable之间,主要用于管理各种ResourceCallBack,根据EngineResource加载的各种状态来通知其余相关的ResourceCallBack以及EngineJobListener。
EngineRunnable
单独开启一个后台Thread 解析资源,解析流程和加载缓存流程相反,
1、分别查看缓存中已经转换的资源和转换之前的资源
2、使用资源的源重新加载缓存
其中EngineRunnable中包括一个接口:
EngineRunnableManager在ResourceCallBack的基础上添加了新的方法:submitForSource(),因为EngineResource需要从缓存中加载,不仅包括加载成功、失败,而且当加载失败时需要重新请求获取资源。
Request
请求封装类
RequestBuilder:
Request相应的创建类,由于Request需要太多的参数,在RequestBuilder中有了默认的参数,然后提供设置方法让用户自定义,从其继承结构可以看出,具体实现类BitmapTypeRequst给人的感觉更像Request而不是RequestBuilder,不晓得为何如此命名。
在解码过程中,就涉及到数据的传递,如何从最初始的字符串或者其他获取到最后的图片信息
主要过程包括 Decode 、Transform 、Transcode 三个过程
1、Decode:从原始数据(字符串)获取图片资源
2、Transform:根据自定义的属性来对获取的资源进行裁剪、转换,默认实现返回原始资源
3、Transcode :用于资源的格式转换,默认实现返回原始资源
其中在每一个过程中都包括一个encode过程,将每一步获取的资源进行缓存。详细的数据加载流程见后文。
DecodeJob
DataFetcher
ResourceDecoder:
Downsample:
ResourceTranscoder:
FitCenter:
TransformationUtils:
ResourceTranscoder:
当资源从缓存或者从其他地方获取到时,则通过如下的流程逐步调用到Target ,将获取到的资源设置其中。
Glide 中使用Fragment 作为媒介,将任务调度的LifeCycleListener与Activity/Fragment 的生命周期事件进行绑定,在当前Activity/Fragment中启动、暂停request请求,主要LifecycleListener的实现包括:RequestManager、Target以及ConnectivityMonitor(监听网络状态)而且,通过RequestManagerTreeNode来保存当前Context所对应的RequestManager来管理当前Context下的所有请求。
在初始化的过程中,主要建立RequestManager、RequestManagerFragment、LifecycleListener之间的关系。
RequestManagerFragment 主要作用是在其生命周期方法中调用实现了LifecycleListener的各个监听的生命周期方法
调度的图示如下:
从网络请求图片这个过程,来说明在整个过程中的数据加载流
从url加载图片这个过程中来分析整个过程,考虑到了如下的问题:
1、如何获取Url?
2、解析到图片之后是否需要其他处理?
所以主要分为三部分:
请求前:根据提供的信息获取真正的数据源(InputStream)
请求;
请求后:图片格式转换
从而可以看出,在Glide中将这整个过程划分的很细致,每一部分都可以重写自定义
从中可以看出从“脏数据”到真正需要的图片所需要的整个过程。Model可以视为“脏数据”(待处理的数据源),ModelLoader
其中需要考虑请求网络图片的url如何获取,获取到的图片是否需要转换、转码
备注:
Model :“脏数据”(待处理的数据源)
ModelLoader中将“脏数据源”转换为真正的数据源,比如将 String——>InputStream 当把ModelType视作脏数据时,其实就是把ModelLoader看做成了判断、转换、预处理的过程。在脏数据与数据源之间就可以添加一个预处理操作,可以进行一些额外的限制(url长度限制)、数据格式转换:比如如下这个案例,在这个实例中,需要根据文件Id来获取图片资源,所以文件Id可以看做脏数据,也叫做待处理的数据源,通过重写ModelLoader,将脏数据转换成数据源,其中可以添加两个网络请求,来获取真正获取图片的InputStream
,其中http://www.licheedev.com/2015/09/19/custom-glide-modelloader/ 在这个案例中,请求图片并不是给了url,而是根据id从服务器请求url,所以加载一次图片,得请求两次服务器,所以,一种可以采纳的策略是重写ModelLoader,传入id ,在其中进行一次网络请求,获取真正的InputStream ,从而充分利用了Glide。
Data:数据源(真正的数据源 InputStream)
Decode:进行一次网络请求,解析资源获取图片通过DataLoadProvinder的,其中提供了两个encode的缓存操作,其一是对数据源、另一个是对图片源缓存
Resource:图片源(从网络请求的图片)
Transform:转换图片(对图片进行裁剪等转换)
Transcode:对图片进行格式转换
Encode:缓存图片到本地
从数据处理的过程中就可以看出,Glide将图片加载从源头到图片都分布完成了,更方便的自定义操作,通过 ModelLoader、DataLoadProvinder、ResourceDecoder、Encoder之间的交互,将整个流程连接起来。
总结下来:
ModelLoader:加载数据预处理,校验、转换操作
DataLoadProvinder:从数据源获取数据,提供了数据源和请求数据的缓存操作的封装
1、自定义ModelLoader、DataFetcher获取网络图片
http://www.licheedev.com/2015/09/19/custom-glide-modelloader/
2、Downloadin-custom-sizes-with-Glide
https://github.com/bumptech/glide/wiki/Downloading-custom-sizes-with-Glide
3、Google推荐的图片加载库Glide介绍
http://blog.csdn.net/jianghejie123/article/details/44725649
4、Glide详解
http://blog.csdn.net/xx326664162/article/details/50373676
5、图片加载框架Glide解析
http://blog.csdn.net/u011228356/article/details/45026431