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架构资料。

  • 35 views
    a
发布日期:2021年09月08日 11:00:00  所属分类:知识经验
标签:
  • 37000.com威尼斯的版权声明: 本站原创文章,由 惠州seo 发表
  • 转载请注明: glide原理方法