![](https://img.haomeiwen.com/i3117364/d1c8a1d8630118aa.jpg)
作者:爱雨浮龙
一、图片
1、图片库对比
2、LRUCache原理
3、图片加载原理
4、自己去实现图片库,怎么做?
5、Glide源码解析
6、Glide使用什么缓存?
7、Glide内存缓存如何控制大小?
参考答案:
1、图片库对比
Picasso Glide Fresco
Picasso 毕加索 Square
Picasso 没有实现本地缓存功能,交给了 Square 的另外一个网络库 okhttp 去实现,
这样的好处是可以通过请求 Response Header 中的 Cache-Control 及 Expired 控制图片的过期时间。
- 使用简单,代码简洁
- 与
Square
其他类库搭配兼容性好,Retrofit OkHttp
等
缺点:
- 功能简单 图片加载
- 性能(加载速度等等)较(
Glide
、Fresco
)差 - 自身没有实现"本地缓存"
Glide Google 开源
支持 Gif WebP Video
生命周期继承
高效缓存策略
- 支持
Memory
和Disk
缓存 -
Picasso
只会缓存原始尺寸图片,而Glide
缓存时多种规格 - 内存开销小,默认
RGB_565
,Picasso
默认是ARGB_8888
缺点:
- 使用方法复杂,实现方法较多
- 使用比
Fresco
简单,但性能(加载&缓存)却比不上Fresco
Fresco Facebook
- 大大减少
OOM
,底层使用C++
技术解决图片缓存问题 - 使用加单,几乎全部功能都能在
xml
上定制
缺点:
- 用法变得更加复杂
- 依赖包更大了
2~3M
- 底层
C++
,阅读源码困难
对比项 | Picasso | Glide | Fresco |
---|---|---|---|
地址 | github.com/square/pica… | github.com/bumptech/gl… | github.com/facebook/fr… |
发布时间 | 2013年5月 | 2014年9月 | 2015年5月 |
是否支持gif | false | true | true |
是否支持webP | true | true | true |
视频缩略图 | false | true | true |
大小 | 100k | 500 KB | 2~3M |
加载速度 | 中 | 高 | 高 |
Disk+Men Cache | true | true | true |
Easy of use | low | mediun | difficult |
star | 13160 | 14709 | 12444 |
开发者 | Square主导 | Google主导 | Facebook主导 |
详细属性对比
对比项 | Glide | Fresco |
---|---|---|
配置 | compile 'com.github.bumptech.glide:glide:XXX.XXX' | compile 'com.facebook.fresco:fresco:XXX.XXX |
初始化 | 直接使用 | Fresco.initialize(this); |
layout | 普通ImageView | 独有的SimpleDraweeView |
圆角, 圆形 | 需要自己实现圆角,继承自BitmapTransformation操作bitmap对象实现 | 通过RoundingParams设置参数 |
缓存 | Glide内存和磁盘缓存 | 三级缓存,分别是 Bitmap缓存,未解码图片缓存, 文件缓存。 |
缓存图像大小 | Glide则会根据ImageView控件尺寸获得对应的大小的bitmap来展示,从而缓存也可以针对不同的对象:原始图像(source),结果图像(result) | 缓存原始图像 |
加载策略 | Glide只有占位图 | 先加载小尺寸图片,再加载大尺寸的 |
加载进度 | false | true |
Bitmap myBitmap = Glide.with(上下文)
.load(url)
.asBitmap() //必须
.get()
//同样在DataSubscriber中获取
FileBinaryResource resource = (FileBinaryResource) Fresco.getImagePipelineFactory().getMainFileCache().getResource(new SimpleCacheKey(url));
if (resource != null && resource.getFile() != null) {
setImage(ImageSource.uri(Uri.fromFile(resource.getFile())));
}
2、LRUCache原理
LruCache DiskLruCache
LruCache是Android 3.1
所提供的一个缓存类DisLruCache
目前在Android
还不是Android SDK
的一部分,但Android
官方文档推荐使用该算法来实现硬盘缓存。
LinkedHashMap
它使用了一个双向链表来存储Map
中的Entry
顺序关系,这种顺序有两种,一种是LRU
顺序,一种是插入顺序
put()
重要的就是在添加过缓存对象后,调用trimToSize()
方法,来判断缓存是否已满,如果满了就要删除近期最少使用的算法。
trimToSize()
方法不断地删除LinkedHashMap
中队头的元素,即近期最少访问的,直到缓存大小小于最大值
LruCache
中维护了一个集合LinkedHashMap
,该LinkedHashMap
是以访问顺序排序的。当调用put()
方法时,就会在结合中添加元素,并调用trimToSize()
判断缓存是否已满,如果满了就用LinkedHashMap
的迭代器删除队头元素,即近期最少访问的元素。当调用get()
方法访问缓存对象时,就会调用LinkedHashMap
的get()
方法获得对应集合元素,同时会更新该元素到队尾。
3、图片加载原理
![](https://img.haomeiwen.com/i3117364/359dd9e272955679.png)
![](https://img.haomeiwen.com/i3117364/29c229d93a16ee3b.png)
4、自己去实现图片库,怎么做?
图片的同步加载
图片的异步加载
图片压缩
内存缓存
磁盘缓存
网络拉取
5、Glide源码解析
![](https://img.haomeiwen.com/i3117364/f73d80ad9047a4e4.png)
![](https://img.haomeiwen.com/i3117364/b014bde6ff2357a3.png)
![](https://img.haomeiwen.com/i3117364/fe91252e549df53e.png)
RequestManager with(Context context)
RequestManager with(android.app.Activity)
RequestManager with(android.app.Fragment)
RequestManager with(android.support.v4.app.Fragment)
RequestManager with(android.support.v4.app.FragmentActivity)
无论使用什么参数,最终都会进入如下三个方法创建 RequestManager
:
RequestManager fragmentGet(Context context, android.app.FragmentManager fm);
RequestManager supportFragmentGet(Context context,
android.support.v4.app.FragmentManager fm);
RequestManager getApplicationManager(Context context);
结论:
-
Activity--FragmentManager--RequestManagerFragment--RequestManager
,所以一个Activity
对应一个RequestManager
- 一个
Fragment
对应一个RequestManager
-
Activity
包含Fragment
,Fragment
包含Fragment
,若分别创建Glide
请求是并不会只创建一个RequestManager
的 - 子线程发起
Glide
请求或传入对象为ApplicationContext
,则使用全局单例的RequestManager
创建 RequestBuilder
的load
方法有很多:
RequestBuilder<Drawable> load(@Nullable Bitmap bitmap);
RequestBuilder<Drawable> load(@Nullable Drawable drawable);
RequestBuilder<Drawable> load(@Nullable String string);
RequestBuilder<Drawable> load(@Nullable Uri uri);
RequestBuilder<Drawable> load(@Nullable File file);
RequestBuilder<Drawable> load(@RawRes @DrawableRes @Nullable Integer resourceId);
RequestBuilder<Drawable> load(@Nullable URL url);
RequestBuilder<Drawable> load(@Nullable byte[] model);
RequestBuilder<Drawable> load(@Nullable Object model);
看看有这么多重载方法,没一个都代表不同的加载源。 除此之外还有两个特殊的方法:
RequestBuilder<File> downloadOnly();
RequestBuilder<File> download(@Nullable Object model);
再创建 RequestManager
时会先创建一个不可见的Fragment
,通过FM
加入到当前页面,用这个不可见的Fragment
即可检测页面的生命周期。
Request
主要的实现类有三个:
SingleRequest
ThumbnailRequestCoordinator
ErrorRequestCoordinator
6、Glide使用什么缓存?
![](https://img.haomeiwen.com/i3117364/818371183769fb37.png)
![](https://img.haomeiwen.com/i3117364/bd089a4216d856cb.png)
BitmapPool 大小通过 MemorySizeCalculator 设置;
使用 LRU 算法维护 BitmapPool ;
Glide 会根据 Bitmap 的大小与 Config 生成一个 Key;
Key 也有自己对应的对象池,使用 Queue 实现;
数据最终存储在 GroupedLinkedMap 中;
GroupedLinkedMap 使用哈希表、循环链表、List 来存储数据。
7、Glide内存缓存如何控制大小?
一种是Resource
缓存,一类是Bitmap
缓存。
Resource
缓存: 图片从网络加载,将图片缓存到本地,当需要再次使用时,直接从缓存中取出而无需再次请求网络。
Glide
在缓存Resource
使用三层缓存,包括:
一级缓存:缓存被回收的资源,使用LRU算法(Least Frequently Used,最近最少使用算法)。当需要再次使用到被回收的资源,直接从内存返回。
二级缓存:使用弱引用缓存正在使用的资源。当系统执行gc操作时,会回收没有强引用的资源。使用弱引用缓存资源,既可以缓存正在使用的强引用资源,也不阻碍系统需要回收无引用资源。
三级缓存:磁盘缓存。网络图片下载成功后将以文件的形式缓存到磁盘中。
Bitmap
缓存 通过Bitmap
压缩质量参数:Glide
默认使用RGB_565
,比系统默认使用的ARGB_8888
节省一半的资源,但RGB_565
无法显示透明度。
Bitmap缓存算法:
在Glide中,使用BitmapPool来缓存Bitmap,使用的也是LRU算法。
当需要使用Bitmap时,从Bitmap的池子中取出合适的Bitmap,若取不到合适的,则再新创建。
当Bitmap使用完后,不直接调用Bitmap.recycler()回收,而是放入Bitmap的池子。
8.Fresco 源码分析
![](https://img.haomeiwen.com/i3117364/c5231c312ff1260e.png)
初始化Fresco。
获取DataSource。
绑定Controller与Hierarchy。
从内存缓存/磁盘缓存/网络获取图片,并设置到对应的Drawable层。
![](https://img.haomeiwen.com/i3117364/e7b141952cbde15c.png)
![](https://img.haomeiwen.com/i3117364/0a961db658400d87.png)
缓冲缓存层:由BufferedDiskCache实现,提供缓冲功能。
文件缓存层:由DiskStorageCache实现,提供实际的缓存功能。
文件存储层:由DefaultDiskStorage实现,提供磁盘文件读写的功能。
DiskStorageCache:实现了FileCache接口与DiskTrimmable接口是缓存的主要实现类。
DefaultDiskStorage:实现了DiskStorage接口,封装了磁盘IO的读写逻辑。
BufferedDiskCache:在DiskStorageCache的基础上提供了Buffer功能。
private static final String CONTENT_FILE_EXTENSION = ".cnt"; private static final String TEMP_FILE_EXTENSION = ".tmp"
;
未解码图片内存缓存:由EncodedImage
描述真正的缓存对象。 已解码图片内存缓存:由BitmapMemoryCache
描述真正的缓存对象。
作为一个Android程序员,要学的东西有太多太多了,对于进阶这条路而言,学习是会有回报的!
你把你的时间投资在学习上,就意味着你可以收获技能,更有机会增加收入。
分享我的Android学习PDF大全来学习,这份Android学习PDF大全真的包含了方方面面了,内含Java基础知识点、Android基础、Android进阶延伸、算法合集等等
我的这份学习合集,可以有效的帮助大家掌握知识点。
总之也是在这里帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习
无论是大大小小的面试,要想心理不慌,刷题必不可少!平时写文章更新有点慢,给大家看看我的大厂面试题合集!
计算机基础面试题、数据结构和算法面试题、Java面试题、Android面试题、其他扩展面试题、非技术面试题总共五个章节354页。
面试时HR
也是不可以忽略的环节,我们经常也会遇到很多关于简历制作,职业困惑、HR
经典面试问题回答等有关面试的问题。
有全套简历制作、春招困惑、HR面试等问题解析参考建议。
上述字节跳动真题解析、 Android 知识大全PDF、简历模板可以关注我看个人简介或者简信我免费获取
网友评论