Glide是什么?它是一个在开发Android时用于图片加载的框架。
在GitHub上以“ language:java android ” 进行搜索,并以 Most stars 排序,它排名第5,有17.9k个star(在2017-09-21),是Android图片加载框架在GitHub上排名最靠前的。
不过,
也有一些跟Glide类似的图片加载框架:UniversalImageLoader,Picasso,Fresco等,但每个框架都有自己的优劣,这里不进行对比。
Glide对于开发者来讲(或者对我自己),最大的特点就是简单易用,一行代码就可以加载图片了:
目前(2017-09-21),Glide的最新稳定版为:4.1.1,下面的代码以在这个版本为基础编写。
1. Glide.with()方法
Glide.with()方法,可以接受Context,Activity或Fragment类型的参数。
需要注意的是,with()方法中传入的实例会决定Glide加载图片的生命周期,如果传入的是Activity或者Fragment的实例,那么当这个Activity或Fragment被销毁的时候,图片加载也会停止。如果传入的是ApplicationContext,那么只有当应用程序被杀掉的时候,图片加载才会停止。
也就是说,如果我们是在Activity或Fragment中使用的话,最好传入this,而不是getApplicationContext。
2. load()方法
load()方法,除了可以接受URL之外,还可以接受如下所示的类型:
3. into()方法
into()方法,除了可以接受ImageView,还可以接受自定义的Target,比如:SimpleTarget。
这样我们可以在SimpleTarget中对得到的图片进行处理了。
4. 其他方法
a. 占位图,异常占位图
顾名思义,占位图就是指在图片的加载过程中,我们先显示一张临时的图片,等图片加载出来了再替换成要 加载的图片。
而异常占位图,就是在加载图片出错后显示的图片。
用法如下:
b. 指定图片格式,指定图片大小
指定图片格式:可以使用 asBitmap()、asGif()
指定图片大小:可以使用override()
用法如下:
c. 准备废弃的downloadOnly()方法
在使用downloadOnly时会发现,这个方法准备废弃掉,想了一下,感觉完全可以使用into()到SimpleTarget来代替这个方法,所以,为了防止某个版本此方法的去除,还是不要再使用的好。
d. listener()
这么强大的框架怎能少得了回调监听呢?回调监听的方法只有两个,可以让我们在写代码时处理加载成功和失败的情况,代码如下:
5. Glide怎么做到当Activity或Fragment销毁时,加载图片也会终止?
方法
with()的重载种类非常多,既可以传入Activity,也可以传入Fragment或者是Context。每一个with()方法重载的代码都非常简单,都是先调用RequestManagerRetriever的静态get()方法得到一个RequestManagerRetriever对象。
看
RequestManagerRetriever这类,有很多个get()方法的重载,什么Context参数,Activity参数,Fragment参数等等,实际上只有两种情况而已,即传入Application类型的参数,和传入非Application类型的参数。
我们先来看传入Application参数的情况。如果在Glide.with()方法中传入的是一个Application对象,那么这里就会调用带有Context参数的get()方法重载,然后会用getApplicationManager()方法来获取一个RequestManager对象。其实这是最简单的一种情况,因为Application对象的生命周期即应用程序的生命周期,因此Glide并不需要做什么特殊的处理,它自动就是和应用程序的生命周期是同步的,如果应用程序关闭的话,Glide的加载也会同时终止。
接下来我们看传入非Application参数的情况。不管你在Glide.with()方法中传入的是Activity、FragmentActivity、v4包下的Fragment、还是app包下的Fragment,最终的流程都是一样的,那就是会向当前的Activity当中添加一个隐藏的Fragment。那么这里为什么要添加一个隐藏的Fragment呢?因为Glide需要知道加载的生命周期。很简单的一个道理,如果你在某个Activity上正在加载着一张图片,结果图片还没加载出来,Activity就被用户关掉了,那么图片还应该继续加载吗?当然不应该。可是Glide并没有办法知道Activity的生命周期,于是Glide就使用了添加隐藏Fragment的这种小技巧,因为Fragment的生命周期和Activity是同步的,如果Activity被销毁了,Fragment是可以监听到的,这样Glide就可以捕获这个事件并停止图片加载了。
需要注意的是,
如果我们是在非主线程当中使用的Glide,那么不管你是传入的Activity还是Fragment,都会被强制当成Application来处理。
6. Glide的缓存机制
Glide有两种缓存模块,一个是内存缓存,一个是硬盘缓存。
内存缓存的主要作用是防止应用重复将图片数据读取到内存当中。
硬盘缓存的主要作用是防止应用重复从网络或其他地方重复下载和读取数据。
6.1 缓存key
既然有缓存,肯定有跟缓存相关的key,而这个key的生成是由EngineKeyFactory的buildKey()方法生成的。
6.2 内存缓存
Glide默认是开启内存缓存的,也就是说,当我们使用Glide加载了一张图片之后,这张图片就会被缓存到内存当中,只要在它还没从内存中被清除之前,下次使用Glide再加载这张图片都会直接从内存当中读取,而不用重新从网络或硬盘上读取了。
当然,可以使用skipMemoryCache(true)方法,禁用掉内存缓存功能。
Glide的内存缓存的实现算法使用的是LruCache算法(Least Recently Used),也叫近期最少使用算法,除此之外,Glide还结合了一种弱引用的机制,共同完成了内存缓存功能。
6.3 硬盘缓存
Glide在默认情况下也是开启硬盘缓存的,不过硬盘缓存的并不是原图,而是经过转换后的图片。
硬盘缓存的设置可以有四种参数:
DiskCacheStrategy.NONE: 表示不缓存任何内容。
DiskCacheStrategy.SOURCE: 表示只缓存原始图片。
DiskCacheStrategy.RESULT: 表示只缓存转换过后的图片(默认选项)。
DiskCacheStrategy.ALL : 表示既缓存原始图片,也缓存转换过后的图片。
可以通过diskCacheStrategy()进行设置。
和内存缓存类似,硬盘缓存的实现也是使用的LruCache算法,不过,又使用了自己实现的DiskLruCache工具类。
7. 意外的收获
7.1 可以判断是否在主进程的一个方法
7.2 学到了一个思想
就是前面的第5小节,利用向参数Activity或Fragment类型的实例中添加一个隐藏的fragment来做到监听生命周期的效果。
8. 参看
主要参看了郭霖对Glide分析的系列文章,写得很好很透彻。