glide 是安卓平台上媒体管理和图片框架,它内部封装了媒体解码工具、内存和磁盘缓存以及资源池等,并向用户暴露简单易用的接口。我们可以用它来获取、解码、并展示视频、图片和 gif 动画。如果大家有用过 picasso 应该知道,glide 的使用方式和 picasso 非常相似,甚至很多 api 的名称都一样。glide是一个优秀的图片加载库,它有如下优点:
1. glide可以监听activity的生命周期管理,更加合理的管理图片的加载和释放。
2. 加载质量,picasso默认采用的argb-8888, glide默认采用的是rgb-565,内存占用会减小一半。
3. glide可以加载gif图。
4. 缓存策略和加载速度。picasso缓存的是全尺寸,而glide的缓存的图片和imageview的尺寸相同。glide的这个特点,让加载显得特别的快,而picasso则因为需要在显示之前重新调整大小而导致一些延迟。
5. glide可以通过自定义glidemoudle来完成特殊的加载需求,例如加载加密的图片等。接下来我们就从源码的角度来探究一下 glide 的内部原理。
glide.with(……)
我们来看一下gilde的源码
/**
* begin a load with glide by passing in a context.
*
*
* any requests started using a context will only have the application level options applied and will not be
* started or stopped based on lifecycle events. in general, loads should be started at the level the result
* will be used in. if the resource will be used in a view in a child fragment,
* the load should be started with {@link #with(android.app.fragment)}} using that child fragment. similarly,
* if the resource will be used in a view in the parent fragment, the load should be started with
* {@link #with(android.app.fragment)} using the parent fragment. in the same vein, if the resource will be used
* in a view in an activity, the load should be started with {@link #with(android.app.activity)}}.
*
*
*
* this method is appropriate for resources that will be used outside of the normal fragment or activity
* lifecycle (for example in services, or for notification thumbnails).
*
*
* @see #with(android.app.activity)
* @see #with(android.app.fragment)
* @see #with(android.support.v4.app.fragment)
* @see #with(android.support.v4.app.fragmentactivity)
*
* @param context any context, will not be retained.
* @return a requestmanager for the top level application that can be used to start a load.
*/
public static requestmanager with(context context) {
requestmanagerretriever retriever = requestmanagerretriever.get(); return retriever.get(context);
}
/**
* begin a load with glide that will be tied to the given {@link android.app.activity}’s lifecycle and that uses the
* given {@link activity}’s default options.
*
* @param activity the activity to use.
* @return a requestmanager for the given activity that can be used to start a load.
*/
public static requestmanager with(activity activity) {
requestmanagerretriever retriever = requestmanagerretriever.get(); return retriever.get(activity);
}
/**
* begin a load with glide that will tied to the give {@link android.support.v4.app.fragmentactivity}’s lifecycle
* and that uses the given {@link android.support.v4.app.fragmentactivity}’s default options.
*
* @param activity the activity to use.
* @return a requestmanager for the given fragmentactivity that can be used to start a load.
*/
public static requestmanager with(fragmentactivity activity) {
requestmanagerretriever retriever = requestmanagerretriever.get(); return retriever.get(activity);
}
/**
* begin a load with glide that will be tied to the given {@link android.app.fragment}’s lifecycle and that uses
* the given {@link android.app.fragment}’s default options.
*
* @param fragment the fragment to use.
* @return a requestmanager for the given fragment that can be used to start a load.
*/
@targetapi(build.version_codes.honeycomb)
public static requestmanager with(android.app.fragment fragment) {
requestmanagerretriever retriever = requestmanagerretriever.get(); return retriever.get(fragment);
}
/**
* begin a load with glide that will be tied to the given {@link android.support.v4.app.fragment}’s lifecycle and
* that uses the given {@link android.support.v4.app.fragment}’s default options.
*
* @param fragment the fragment to use.
* @return a requestmanager for the given fragment that can be used to start a load.
*/
public static requestmanager with(fragment fragment) {
requestmanagerretriever retriever = requestmanagerretriever.get(); return retriever.get(fragment);
}
总结:可以传入的参数有
*@see #with(android.app.activity)
* @see #with(android.app.fragment)
* @see #with(android.support.v4.app.fragment)
* @see #with(android.support.v4.app.fragmentactivity)
同时将activity/fragment作为with()参数的好处是:图片加载会和activity/fragment的生命周期保持一致,比如paused状态在暂停加载,在resumed的时候又自动重新加载。所以我建议传参的时候传递activity 和 fragment给glide,而不是context。
接下来我想说glide的原理,下图是glide原理简图。
glide原理简图
1.glide的资源获取组件:
· model: 原始资源,比如url,androidresourceid, file等
· data: 中间资源,比如stream,parcelfiledescriptor(contentprovider共享文件时比较常用,其实就是操作系统的文件描述符的封装,里面有in out err三个取值。也有人说是链接建立好之后的socket句柄。)等
· resource:直接使用的资源,包括bitmap,drawable等
2.glide库的资源复用:
· android的内存申请几乎都在new的时候发生,而new较大对象(比如bitmap时),更加容易触发gc_for_allow。所以glide尽量的复用资源来防止不必要的gc_for_alloc引起卡顿。
· 最显著的内存复用就是内存lruresourcecache(第一次从网络或者磁盘上读取到resource时,并不会保存到lrucache当中,当resource被release时,也就是view不在需要此resource时,才会进入lrucache当中)
· 还有bitmappool(glide会尽量用图片池来获取到可以复用的图片,获取不到才会new,而当lrucache触发evicted时会把从lrucache中淘汰下来的bitmap回收,也会把transform时用到的中间bitmap加以复用及回收)
3.glide库图片池:
· 以前是bitmap复用必须长宽相等才可以复用
· 及以后是size>=所需就可以复用,只不过需要调用reconfigure来调整尺寸
· glide用attributestategy和sizestrategy来实现两种策略
· 图片池在收到传来的bitmap之后,通过长宽或者size来从keypool中获取key(对象复用到了极致,连key都用到了pool),然后再每个key对应一个双向链表结构来存储。每个key下可能有很多个待用bitmap
· 取出后要减少图片池中记录的当前size等,并对bitmap进行erasecolor(color.transpaent)操作确保可用
4.glide加载发起流程:
1. glide.with(context)创建requestmanager
· requestmanager负责管理当前context的所有request
· context可以传fragment、activity或者其他context,当传fragment、activity时,当前页面对应的activity的生命周期可以被requestmanager监控到,从而可以控制request的pause、resume、clear。这其中采用的监控方法就是在当前activity中添加一个没有view的fragment,这样在activity发生onstart onstop ondestroy的时候,会触发此fragment的onstart onstop ondestroy。
· requestmanager用来跟踪众多当前页面的request的是requesttracker类,用弱引用来保存运行中的request,用强引用来保存暂停需要恢复的request。
2. glide.with(context).load(url)创建需要的request
· 通常是drawabletyperequest,后面可以添加transform、fitcenter、animate、placeholder、error、override、skipmemorycache、signature等等
· 如果需要进行resource的转化比如转化为byte数组等需要,可以加asbitmap来更改为bitmaptyperequest
· request是glide加载图片的执行单位
3. glide.with(context).load(url).into(imageview)
· 在request的into方法中会调用request的begin方法开始执行
· 在正式生成enginejob放入engine中执行之前,如果并没有事先调用override(width, height)来指定所需要宽高,glide则会尝试去获取imageview的宽和高,如果当前imageview并没有初始化完毕取不到高宽,glide会通过view的viewtreeobserver来等view初始化完毕之后再获取宽高再进行下一步
5.glide加载资源:
· glidebuilder在初始化glide时,会生成一个执行机engine
· engine中包含lrucache缓存及一个当前正在使用的active资源cache(弱引用)
· activecache辅助lrucache,当resource从lrucache中取出使用时,会从lrucache中remove并进入acticecache当中
· cache优先级lrucache>activecache
· engine在初始化时要传入两个executorservice,即会有两个线程池,一个用来从diskcache获取resource,另一个用来从source中获取(通常是下载)
· 线程的封装单位是enginejob,有两个顺序状态,先是cachestate,在此状态先进入diskcacheservice中执行获取,如果没找到则进入sourcestate,进到sourceservice中执行下载
6.glide的target:
负责图片加载的回调。
以上便是 glide 的源码和原理,它内部的运作实在是太复杂了,但正是这种复杂的内部实现使得 glide 的可扩展型得到增强。比如我们可以自定义磁盘缓存策略,自定义 modelloader 以实现 model 到 data 的转换,也可以自定义 resourcedecoder 和 resourcetranscoder 来实现资源的解码和转码。用一张图来总结整个加载过程:
好啦,文章写到这里就结束了,如果你觉得文章写得不错就给个赞呗!如果你觉得那里值得改进的,请给我留言。一定会认真查阅,修正不足。谢谢!更多更详细更专业android架构资料。