}
public RequestBuilder error(@DrawableRes int resourceId) {
// 设置错误图片
return this;
}
}
既然有了RequestBuilder,那么最终是为了构建请求,那么小明还得设计出一个用于获取图片的Request,设计出来后的效果如下:
public interface Request {
// 开始请求
void begin();
// 清除请求
void clear();
// 暂停请求
void pause();
}
请求类已经设计好了,那么在Request的begin的时候就开始获取图片;
当图片请求完之后,或者加载失败,加载展位图,都需要对控件进行设置,因此还需要设计一个类,专门用于设置图片控件;
于是小明设计出了一个ImageViewTarget,用于设置图片控件,请看下面的伪代码;
public class ImageViewTarget {
public void onLoadStarted(@Nullable Drawable placeholder) {
// 开始加载,设置图片展位图
}
public void onLoadFailed(@Nullable Drawable errorDrawable) {
// 加载失败,设置图片加载失败展位图
}
public void onResourceReady(@NonNull Drawable resource) {
// 加载成功,设置图片
}
}
那么将这个简单组合一个,就成了一个小小的“框架”,有了获取图片进行加载的功能了;
当然,我这里省略了部分代码,你只要知道大概的加载流程就可以了,不必深究细节;
(1)通过RequestBuilder构建请求Request;
(2)通过RequestManager管理Request;
(3)Request请求成功或者失败回调ImageViewTarget设置给图片控件;
很简单,三步实现了一个小小的图片“框架”;
3、第三版本实现
第一步我们已经简单实现了,通过网络请求,加载图片,设置给控件;
但是每一次都从网络上获取图片,在现实情况下,是非常不合理的;
因为每次都从网络上获取,不但会导致网络资源的浪费,并且还会影响加载速度,万一遇到网络不好的情况下,就容易加载很久才出来;
那么我们再对上面这个框架进行进一步的改造;
怎么改造呢? 很简单,引入缓存机制;
众所周知,Android的缓存机制可以分为几种,一种是网盘缓存,一种是磁盘缓存,一种是内存缓存;
那么我们就可以根据这三种情况来设计出具有三级缓存的图片加载机制;
一个简单的缓存机制就设计完成了,接下来就是代码实现了;
要加载图片缓存机制,我们可以先设计出一个引擎类Engine,用来加载图片的三级缓存;
那么设计出来后大概是这个样子:
public class Engine {
public void load() {
// 从三级缓存里面加载图片
}
private Bitmap loadFromMemory() {
// 从缓存里获取图片
return null;
}
private Bitmap loadFromCache() {
// 从磁盘里获取图片
return null;
}
private Bitmap loadFromNetWork() {
// 从网络里获取图片
return null;
}
}
3.1、内存缓存的设计
首先是内存缓存,内存缓存的设计,非常的重要,因为涉及到图片的回收;
回收早了,那么内存的缓存起不到实际作用,回收慢了,又会占用内存,浪费内存空间;
那么这个图片缓存的算法要怎么设计呢?
有一个著名算法,就是最近最少使用算法,非常适合用来做内存缓存的回收;
什么叫最近最少使用算法,当然字如其名;
即:长期不被使用的数据,在未来被用到的几率也不大。因此,当数据所占内存达到一定阈值时,要移除掉最近最少使用的数据。
具体的算法逻辑可以看下这个:什么是LRU(最近最少使用)算法?
那么我们这里就可以用这个算法来设计图片缓存;
public class LruResourceCache<T, Y> {
private final Map<T, Y> cache = new LinkedHashMap<>(100, 0.75f, true);
public synchronized Y put(@NonNull T key, @Nullable Y item) {
// 缓存图片
return null;
}
public synchronized Y get(@NonNull T key) {
// 获取图片
return null;
}
public void clearMemory() {
// 清除所有缓存
trimToSize(0);
}
protected synchronized void trimToSize(long size) {
// 回收内存到指定大小,将最近最少使用的,移除到指定大小
}
}
这里设计了几个方法,存和取的操作,还有清除缓存,回收图片内存的操作;
这时候你是否有疑问,我存取图片的key要用那个呢?
很简单,用图片的url,因为每一张图片的url都是不一样的,所以可以把这个作为唯一的key;
那么这个简单的内存缓存就设计好了;
接下来我们来看看磁盘缓存要怎么设计;
3.2、磁盘缓存的设计
磁盘缓存的设计,其实没有那么复杂,无非就是将图片文件存储到手机存储卡里,读也是从存储卡里读;
和内存不同的是,从磁盘里读写的速度较慢,好处就是,磁盘可以存储比内存更多更大的图片文件;
因为和内存相比,存储卡的容量要远远高于内存的大小;
和内存意义,我们设计了一个读,一个写的操作; 读:负责从磁盘读取图片文件 写:负责将图片文件写入到磁盘
public class DiskLruCache {
public synchronized T get(String key){
// 获取磁盘的数据
return null;
}
public synchronized void put(String key, T value){
// 存储图片数据到磁盘中
}
}
3.3、网络缓存的设计
网络缓存的设计就很简单了,也就是直接访问获取,获取图片文件;
public class NetWorkLruCache {
public synchronized T request(String url){
// 获取网络的数据
return null;
}
}
那么到这里,一个简单的缓存机制就设计完成了;
3.4、总结
那么一个简单的图片框架就这样实现了,相较于之前的框架,多了缓存机制,对于图片的利用有了很大的提升;
如果我告诉你,恭喜你,你已经成功掌握了Glide源码的实现,我想我可能会被一巴掌拍扁了;
但是我想要告诉你的是,上面的原理,就是一个Glide源码的简化,看懂了上面那个逻辑,基本上Glide源码的基本流程,你就已经搞懂了;
剩下的基本上就是更加细节的实现;
事实上,一个图片框架的实现基本上离不开这几步,更细节的实现,无非就是基于这几步来进行扩展,封装;
基础的原理搞明白了,再去深入研究源码,才会有意义;
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后看一下学习需要的所有知识点的思维导图。在刚刚那份学习笔记里包含了下面知识点所有内容!文章里已经展示了部分!如果你正愁这块不知道如何学习或者想提升学习这块知识的学习效率,那么这份学习笔记绝对是你的秘密武器!
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!
d开发知识点,真正体系化!**
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)
最后看一下学习需要的所有知识点的思维导图。在刚刚那份学习笔记里包含了下面知识点所有内容!文章里已经展示了部分!如果你正愁这块不知道如何学习或者想提升学习这块知识的学习效率,那么这份学习笔记绝对是你的秘密武器!
[外链图片转存中…(img-GnqDVQ30-1712538788238)]
《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!