详解Android GLide图片加载常用几种方法
Coolbreeze 人气:0缓存浅析
为啥要做缓存? android默认给每个应用只分配16M的内存,所以如果加载过多的图片,为了 防止内存溢出 ,应该将图片缓存起来。
图片的三级缓存分别是:
- 1、内存缓存
- 2、本地缓存
- 3、网络缓存 其中,内存缓存应优先加载,它速度最快;本地缓存次优先加载,它速度也快;网络缓存不应该优先加载,它走网络,速度慢且耗流量。
最优-优先级:内存缓存 > 本地缓存 > 网络缓存
- 两个方法实现:根据图片的url去加载图片、在本地和内存中缓存
- 两个方法实现:设置本地缓存,以及获取本地缓存
- 两个方法实现:设置内存缓存,获取内存缓存。
如果使用hashmap去存储图片时,当图片越来越多,那么会造成内存溢出,因为是强引用(对于强引用的系统不会回收)
如果改成软引用softReference,在android 2.3 以上的系统,对象会被提前回收。
可以用LruCache来解决上述内存不回收或提前回收的问题。least recentlly use 最少最近使用算法 它会将内存控制在一定的大小内, 超出最大值时会自动回收, 这个最大值开发者自己定。(这个东西没有用过..)
GLide图片加载方法
图片加载周期
Glide最简单的用法:
Glide.with(context).load(url).into(imageView)
with()方法中传入的Context实例会决定Glide加载图片的生命周期,如果传入的是Activity或者Fragment的实例,那么当这个Activity或Fragment被销毁的时候,图片加载也会停止。如果传入的是ApplicationContext,那么只有当应用程序被杀掉的时候,图片加载才会停止。
想法:传入ImageView.getContext()实例是不是最好的方案,ImageView所在的Context销毁了,图片自然应该取消加载。此方案是否可行?列表的回收机制会不会有问题?
结论:不是最好的方案,fragment和adapter中ImageView.getContext()返回的都是Activity,当fragment或adapter销毁但activity并没有销毁时,图片仍会加载,所以声明周期并不合理
图片格式(Bitmap,Gif)
Glide是支持加载GIF图片的,不需要编写额外的代码,Glide内部会自动判断图片格式(Gif图不一定是以.gif后缀结尾的哦。
当然也可以手动指定图片格式: 调用了asBitmap()方法,静态图正常加载,GIF图无法正常播放,会在界面上显示第一帧的图片; 调用了asGif()方法,GIF图正常加载和播放,静态图加载失败。
想法:一般情况下不需要指定图片格式,动图的播放机制(一直循环播放/只播放一次)怎么设置?默认是循环播放
结论:设置监听,回调中设置播放次数,如下:
Glide.with(this) .load(url) .addListener(new RequestListener<Drawable>() { @Override public boolean onLoadFailed( @Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { if (resource instanceof GifDrawable) { //设置播放次数 ((GifDrawable) resource).setLoopCount(3); } return false; } }) .into(iv);
缓存
在缓存这一功能上,Glide又将它分成了两个模块,一个是内存缓存,一个是硬盘缓存。 默认情况下,Glide自动就是开启内存缓存和磁盘缓存的。 磁盘缓存是存在哪的?是否需要动态权限,未授权时磁盘缓存是不是就失效了?
结论:磁盘缓存默认存储在应用内部文件,访问应用内部文件无需动态申请权限
集成网络框架
Glide默认使用的是HttpUrlConnection,支持集成Volley,Okhttp等其它网络栈。 想法:一般用的时候没有集成过网络栈,如何集成?
权限
一般使用场景是加载网络图片,Internet权限肯定是要的,但还有个小细节:如果你正在从 URL 加载图片,Glide 可以自动帮助你处理片状网络连接:它可以监听用户的连接状态并在用户重新连接到网络时重启之前失败的请求。如果 Glide 检测到你的应用拥有 ACCESS_NETWORK_STATE 权限,Glide 将自动监听连接状态而不需要额外的改动。
占位符
- placeHolder
- error
- fallback
占位图是否会影响控件的大小? 结论:不会,网上有人说会有问题,我用的Glide4.9版本试的,可能Glide已经修复了
淡入效果
transitionOption
变换
缩放模式适配不同场景:
启动页/广告页
全屏展示(填充宽高),不变形,尽可能少的裁剪内容[我特地问了做设计的朋友,他们是有设计规范的,四周不会放内容,xx像素内是内容区域。所以适当的裁剪掉边上的内容是没有问题的]。使用centerCrop就可满足上述条件。
banner
banner一般都是以ViewPager做容器,ViewPager的高度是不支持wrap_content的,也就是说要么指定高度,要么match_parent。banner的宽一般是固定的,高度若是写死,采用fitXY在有些手机上会有变形;fitCenter周边可能会有留白;centerCrop又会裁剪掉边上的内容 (banner一般要求不能裁剪,本来区域就不大,你还裁剪,可能会丢失重要内容)。
宽固定,高根据图片比例算出控件高,设置给ViewPager,因为viewPager会预加载两边的view,所以适配的前提是所有banner图片宽高比一致(一般都能满足)
Glide.with(context) .load(url) .addListener(new RequestListener<Drawable>() { @Override public boolean onLoadFailed(@Nullable GlideException e, Object model, Target<Drawable> target, boolean isFirstResource) { return false; } @Override public boolean onResourceReady(Drawable resource, Object model, Target<Drawable> target, DataSource dataSource, boolean isFirstResource) { //根据图片宽高比设置容器的高度 int intrinsicWidth = resource.getIntrinsicWidth(); int intrinsicHeight = resource.getIntrinsicHeight(); int height = intrinsicHeight * width / intrinsicWidth; layoutParams.height = height; return false; } }) .override(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) .transform(new RoundedCorners(10)) .into(imageView);
固定宽高
图片不变形,不裁剪,fitCenter即可满足。
圆角
RoundedCorners
圆形
CircleCrop
不得不说Glide的设计真的满足了我们99%的场景需求了。
以上是许多大厂中喜欢使用的图片加载方法,这里简单的举例Glide图片加载的几种方案。其中阿里企业就是使用Glide图片加载。有关更多Android技术详解,和更多核心进阶技术。
总结
Glide是Android开发中常用的图片框架,其最基本用法例如Glide.with(context).load(url).into(imageView),我们沿着此链式调用的顺序一窥Glide图片加载流程的样貌。
一图胜千言
加载全部内容