by hzwusibo 20190504
优点:
支持gif
链式调用 ( 编程性强、 可读性强 、 代码简洁)
glide三级缓存
Glide会自动判断ImageView的大小,然后只将这么大的图片像素加载到内存当中,帮助我们节省内存开支。
对象池的使用生命周期绑定:图片的加载任务会与activity或者Fragment的生命周期绑定,当界面执行onStop的使用自动暂定,而当执行onStart的时候又会自动重新开启,同样的,动态Gif图的加载也是如此,以用来节省电量,
同时Glide会对网络状态做监听,当网络状态发生改变时,会重启失败的任务,以减少任务因网络连接问题而失败的概率。
预览图的使用
Q1:看过Glide源码吗,你印象最深的是什么?
Glide的缓存设计非常先进,考虑的场景也很周全。在缓存上Glide 分成了两个模块,一个是内存缓存,一个是硬盘缓存。
这两个缓存模块的作用各不相同,内存缓存的主要作用是防止应用重复将图片数据读取到内存当中,而硬盘缓存的主要作用是防止应用重复从网络或其他地方重复下载和读取数据。
Q2:简单说一下Glide的三级缓存?
Glide缓存机制大致分为三层:内存缓存、弱引用缓存、磁盘缓存。
存的顺序是:弱引用、内存、磁盘
取的顺序是:内存、弱引用、磁盘
Q3: glide三级缓存,glide加载一个一兆的图片(100*100),是否会压缩后再加载,放到一个200*200的view上会怎样,1000*1000呢,图片会很模糊,怎么处理?
而使用Glide,我们不用担心图片内存浪费,内存溢出的问题。因为Glide不会直接将图片的完整尺寸全部加载到内存中,而是用多少加载多少。Glide会自动判断ImageView的大小,然后只将这么大的图片像素加载到内存当中,帮助我们节省内存开支。
安卓图片显示的质量配置主要分为四种:
ARGB_8888 :32位图,带透明度,每个像素占4个字节
ARGB_4444 :16位图,带透明度,每个像素占2个字节
RGB_565 :16位图,不带透明度,每个像素占2个字节
ALPHA_8 :32位图,只有透明度,不带颜色,每个像素占4个字节
Glide的默认质量则为 RGB_565
Picasso的默认质量是 ARGB_8888
Glide也并没有使用什么神奇的魔法,它内部的实现原理其实就是insmaplesize技术,
Android高效加载大图、多图解决方案,有效避免程序OOM
https://blog.csdn.net/guolin_blog/article/details/9316683
inSampleSize优化
https://www.jianshu.com/p/f15cd2ed6ec0
一个可选的BitmapFactory.Options参数,将这个参数的inJustDecodeBounds属性设置为true就可以让解析方法禁止为bitmap分配内存,返回值也不再是一个Bitmap对象,而是null。虽然Bitmap是null了,但是BitmapFactory.Options的outWidth、outHeight和outMimeType属性都会被赋值。
inSampleSize的默认值和最小值为1(当小于1时,解码器将该值当做1来处理),且在大于1时,该值只能为2的幂(当不为2的幂时,解码器会取与该值最接近的2的幂)。例如,当inSampleSize为2时,一个20001000的图片,将被缩小为1000500,相应地,它的像素数和内存占用都被缩小为了原来的1/4:
Glide VS Picasso
不仅仅是 Google的推荐,支持 GIF 。 在没有 Glide 之前,常用的做法就是写了个自定义 view 然后 用一个 media 去播放。有了 Glide 之后可以像普通图片那样去加载并且显示出来动图。
Glide VS fresco
fresco 最大只支持图片文件大小为 2M 。有时候大的时候, Glide 正常显示, fresco显示黑屏。。。
fresco 更多是native实现。所以需要对NDK有所了解,,相比较于 Glide, 同样遇到问题之后,修改源码的成本,Glide 更方便。
Glide VS Android-Universal-Image-Loader
已经不再维护的开源库,
Android碎片化那么严重,我们自己维护起来还是要考虑成本的。所以 Glide 胜出。
Glide 支持功能更多。 比如 BitmapTransformation,比如圆形,圆角等。
更多变换
在图片组件中我实现了三种自定义变换,包含圆形,圆角和模糊。
网上也有很多Glide的图片变换开源库,我感觉做的最好的是glide-transformations这个库了吧。它实现了很多通用的图片变换效果,如裁剪变换、颜色变换、模糊变换等等,使得我们可以非常轻松地进行各种各样的图片变换。不过我们用不到那么多功能的话也不需要依赖一个三方库了吧,主要还是要学习为主。
Glide 是如何解决图片加载生命周期的?
Glide 的使用方式上,一定需要传入一个 context 给它。可以根据不同的上下文进行处理,拿到 context (除了application context)之后,Glide做了一件很巧妙的事情,就是在这个界面上追加一个 fragment,由于 fragment 添加到了 activity 上,是可以捕获到生命周期的,因此可以在 destroy 的时候取消掉当前context下的 glide对象中的加载任务。
Glide 坑爹的 wrap_content 不支持的问题
官方说了的,不支持并且不建议imageview设置wrap_content。因为这样 glide 不知道要加载多大的图片给我们才好。 普通的imageview其实也还好,如果放在列表(RecyclerView)中, 由于我们并不知道目标图片大小是多大的,所以我们选择了wrap_content,那么在上下来回滚动过程中,就会导致图片一会大一会小的bug.
Glide Module自定义缓存
图片框架中很多自定义的实现,而缓存也是框架中最为常见的行为之一。因此在开发使用中有些项目需求不凡试下自定义Glide的缓存.
https://blog.csdn.net/qq_38859786/article/details/80291476
源码解析
1,Glide采用的是三级缓存,内存–>磁盘–>网络
Glide的缓存功能,大部分都是在load()方法中进行的
A:内存缓存的主要作用 : 是防止应用重复将图片数据读取到内存当中,
B:磁盘缓存的主要作用 : 是防止应用重复从网络或其他地方重复下载和读取数据。
C:Glide内存缓存的实现使用的LruCache算法。结合弱引用的机制,共同完成了内存缓存功能
3,Glide.with()
With方法有5个重载的构造方法,运行你在activity,frgament或者其他地方使用.得到一个RequestManager对象 ,RequestManager实现了LifeCycleListener接口,绑定Activity/Fragment生命周期,对请求进行暂停,恢复,清除操作.
下面是5个构造方法
//RequestManager实现了LifeCycleListener接口
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
public static RequestManager with(FragmentActivity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
//V4包的fragment
public static RequestManager with(Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
3.1RequestManage对象源码
public class RequestManager implements LifecycleListener {
private final Context context;
private final Lifecycle lifecycle;
private final RequestManagerTreeNode treeNode;
private final RequestTracker requestTracker;
private final Glide glide;
public RequestManager(Context context, Lifecycle lifecycle, RequestManagerTreeNode treeNode) {
this(context, lifecycle, treeNode, new RequestTracker(), new ConnectivityMonitorFactory());
}
RequestManager(Context context, final Lifecycle lifecycle, RequestManagerTreeNode treeNode,
RequestTracker requestTracker, ConnectivityMonitorFactory factory) {
this.context = context.getApplicationContext();
this.lifecycle = lifecycle;
this.treeNode = treeNode;
this.requestTracker = requestTracker;
//通过Glide的静态方法获取实例对象,Glide是通过单利创建的
this.glide = Glide.get(context);
this.optionsApplier = new OptionsApplier();
4,load(url)
Glide的缓存功能,大部分都是在load()方法中进行的
load()也有很多重载的方法,它可以加载网络图片,本地图片,gif(动态图)图,Uri,File,
public DrawableTypeRequest<String> load(String string) {
return (DrawableTypeRequest<String>) fromString().load(string);
}
//加载Uri
public DrawableTypeRequest<Uri> load(Uri uri) {
return (DrawableTypeRequest<Uri>) fromUri().load(uri);
}
//加载File
public DrawableTypeRequest<File> load(File file) {
return (DrawableTypeRequest<File>) fromFile().load(file);
}
//直接加载图片资源id, R.mipmap.ic_launcher
public DrawableTypeRequest<Integer> load(Integer resourceId) {
return (DrawableTypeRequest<Integer>) fromResource().load(resourceId);
}
//加载URL
@Deprecated
public DrawableTypeRequest<URL> load(URL url) {
return (DrawableTypeRequest<URL>) fromUrl().load(url);
}
5,Glide的into()方法
public Target<TranscodeType> into(ImageView view) {
Util.assertMainThread();
if (view == null) {
throw new IllegalArgumentException("You must pass in a non null View");
}
if (!isTransformationSet && view.getScaleType() != null) {
switch (view.getScaleType()) {
case CENTER_CROP:
applyCenterCrop();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
applyFitCenter();
break;
//$CASES-OMITTED$
default:
// Do nothing.
}
}
return into(glide.buildImageViewTarget(view, transcodeClass));
}
最终调用的into方法
//Target我们可以理解成View,只是Glide对我们的View做了一层封装。
public <Y extends Target<TranscodeType>> Y into(Y target) {
//判断是否在主线程,(UI界面更新只能在主线程),不在主线程就报异常
Util.assertMainThread();
if (target == null) {
throw new IllegalArgumentException("You must pass in a non null Target");
}
if (!isModelSet) {
throw new IllegalArgumentException("You must first set a model (try #load())");
}
//获取request对象
Request previous = target.getRequest();
//requestTracker是请求跟踪类对象,主要管理请求的发起,暂停,清除
if (previous != null) {
previous.clear();
requestTracker.removeRequest(previous);
previous.recycle();
}
//创建request对象
Request request = buildRequest(target);
target.setRequest(request);
//将target加入lifecycle,绑定生命周期
lifecycle.addListener(target);
//执行请求
requestTracker.runRequest(request);
return target;
Android图片加载框架最全解析(一),Glide的基本用法
https://blog.csdn.net/guolin_blog/article/details/53759439
Android图片加载框架最全解析(二),从源码的角度理解Glide的执行流https://blog.csdn.net/guolin_blog/article/details/53939176
Android图片加载框架最全解析(五),Glide强大的图片变换功能
https://blog.csdn.net/guolin_blog/article/details/71524668
Android图片加载框架最全解析(七),实现带进度的Glide图片加载功能
https://blog.csdn.net/guolin_blog/article/details/78357251
磁盘缓存
//DiskCacheStrategy.SOURCE:缓存原始数据,
// DiskCacheStrategy.RESULT:缓存变换后的资源数据,
// DiskCacheStrategy.NONE:什么都不缓存,
DiskCacheStrategy.ALL:缓存SOURC和RESULT。
// 默认采用DiskCacheStrategy.RESULT策略
Glide会为每种大小的ImageView缓存一次。尽管一张图片已经缓存了一次,但是假如你要在另外一个地方再次以不同尺寸显示,需要重新下载,调整成新尺寸的大小,然后将这个尺寸的也缓存起来。具体说来就是:假如在第一个页面有一个200x200的ImageView,在第二个页面有一个100x100的ImageView,这两个ImageView本来是要显示同一张图片,却需要下载两次;可以通过改变Glide的行为让它即加载全尺寸图片,也加载不同尺寸图片
Glide.with(this)
.load("http://nuuneoi.com/uploads/source/playstore/cover.jpg")
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(ivImgGlide);
下次在任何ImageView中加载图片的时候,全尺寸的图片将从缓存中取出,重新调整大小,然后缓存。