使用Glide,首先就是要导入一个依赖包(在moudle的Build.gradle里面设置):
compile 'com.github.bumptech.glide:glide:4.0.0-RC0'
如果需要图片戳圆,那就用4.0以上的Glide依赖包
Glide.with(MainActivity.this).load("").into(mImg);
先说说with方法吧,with方法里面可以放,Context,Activity,FragmentActivity,Fragment甚至是View不同的类型,我们来看看源码:
with:
它是通过RequestManager拿到的with里面的属性
public static RequestManager with(FragmentActivity activity) {
return getRetriever(activity).get(activity);
}
RequestManager是实现的LifecycleListenner
public class RequestManager implements LifecycleListener {
而LifeCycleListenner是一个接口,接口里面有三个方法,也就是三个生命周期,从这里可以发现原来activity是和fragment的生命周期绑定的,
因为activity和fragment里面有相同的生命周期。这样就可以明白with后面可以放不同的上下文引用了。
public interface LifecycleListener {
/**
* Callback for when {@link android.app.Fragment#onStart()}} or {@link
* android.app.Activity#onStart()} is called.
*/
void onStart();
/**
* Callback for when {@link android.app.Fragment#onStop()}} or {@link
* android.app.Activity#onStop()}} is called.
*/
void onStop();
/**
* Callback for when {@link android.app.Fragment#onDestroy()}} or {@link
* android.app.Activity#onDestroy()} is called.
*/
void onDestroy();
}
load();
在调用Glide.with()的情况下获得一个requestManager ,会调用这个方法 ,
public RequestBuilder<Drawable> load(@Nullable Object model) {
return asDrawable().load(model);
}
这里并没有直接加载我们获得的Url资源,而是调用asDrawable来配置资源,其实就是说加载的图片是通过drawable,bitmap或者是Gif进行图片显示,图片默认的事drawable格式,你也可以使用asGif或者是asBitmap。
public RequestBuilder<Drawable> asDrawable() {
return as(Drawable.class).transition(new DrawableTransitionOptions());
}
使用load()方法主要是为了获得RequestBuilder对象
protected RequestBuilder(Glide glide, RequestManager requestManager,
Class<TranscodeType> transcodeClass) {
this.glide = glide;
this.requestManager = requestManager;
this.context = glide.getGlideContext();
this.transcodeClass = transcodeClass;
this.defaultRequestOptions = requestManager.getDefaultRequestOptions();
this.requestOptions = defaultRequestOptions;
}
完成asDrawable方法对RequestBuilder的创建后才调用load方法来传递我们的url地址,其实在load也没有做什么事,就是一个中转站,转给了loadGeneric方法
@SuppressWarnings("unchecked")
public RequestBuilder<TranscodeType> load(@Nullable Object model) {
return loadGeneric(model);
}
private RequestBuilder<TranscodeType> loadGeneric(@Nullable Object model) {
this.model = model;
isModelSet = true;
return this;
}
into();
Into()加载图片资源,可以说这个方法是这两个方法里面最难的一个,不管多难我们都要学习。通过这个方法,可以看出来,把传进去的view转化为Target,至于什么样的Target,会根据图片的类型而定
public Target<TranscodeType> into(ImageView view) {
Util.assertMainThread();
Preconditions.checkNotNull(view);
if (!requestOptions.isTransformationSet()
&& requestOptions.isTransformationAllowed()
&& view.getScaleType() != null) {
if (requestOptions.isLocked()) {
requestOptions = requestOptions.clone();
}
switch (view.getScaleType()) {
case CENTER_CROP:
requestOptions.optionalCenterCrop();
break;
case CENTER_INSIDE:
requestOptions.optionalCenterInside();
break;
case FIT_CENTER:
case FIT_START:
case FIT_END:
requestOptions.optionalFitCenter();
break;
case FIT_XY:
requestOptions.optionalCenterInside();
break;
case CENTER:
case MATRIX:
default:
// Do nothing.
}
}
会先判断当前的Target对象有没有Request,如果有的话,直接调用clear()方法清除掉,以节省资源,然后创建新的Request并添加到新的Target上面。
public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) {
Util.assertMainThread();
Preconditions.checkNotNull(target);
if (!isModelSet) {
throw new IllegalArgumentException("You must call #load() before calling #into()");
}
Request previous = target.getRequest();
if (previous != null) {
requestManager.clear(target);
}
requestOptions.lock();
Request request = buildRequest(target);
target.setRequest(request);
requestManager.track(target, request);
return target;
}
关于这个into方法,要是细谈的话,可能看着看着就蒙了,为了让大家好好的理解,就取其中的精华来给大家讲吧,如果需要,可以去深入的了解。
在into();方法里面内存应用:
1,从Lrucache中取,若有数据,那么就在engine类的map中存一份这个资源,key和Lrucache的key是类似的,但是值是弱引用的Lrucache资源,这样就减少了Lrucache可能要移除最近最少使用的图片,然后就减少了再去重新加载的问题,因为它可以去map中去一下图片
2,若Lrucache里没有取到图片,就通过刚才的map中去取。
3,创建一个engineJob去硬盘中读取资源,去判断硬盘缓存策略是什么类型的,然后取出指定类型的图片。
接下来介绍一下Glide的常用方法,以及用Glide对内存的优化:
先介绍一下可以导入的几种图片格式:
// 加载本地图片
File file = new File(getExternalCacheDir() + "/demo.jpg");
Glide.with(this).load(file).into(imageView);
// 加载应用资源
Glide.with(this).load(R.drawable.image).into(imageView);
// 加载二进制流
byte[] image = getImageBytes();
Glide.with(this).load(image).into(imageView);
// 加载Uri对象
Uri imageUri = getImageUri();
Glide.with(this).load(imageUri).into(imageView);
占位图
Glide.with(MainActivity.this)
.load(url)
.placeholder(R.mipmap.placeholder)
.into(mImage);
异常占位图
//错误的图片地址
String url = "http://sc.net/uploads/allimg/150709/14-150FZ94211O4.jpg";
Glide .with(context)
.load(url)
.placeholder(R.mipmap.defalut) //设置占位图
.error(R.mipmap.error) //设置错误图片
.crossFade() //设置淡入淡出效果,默认300ms,可以传参 //.dontAnimate() //不显示动画效果
.into(imageView);
设置下载优先级
• Priority.LOW
• Priority.NORMAL
• Priority.HIGH
• Priority.IMMEDIATE
Glide
.with(context)
.load(url)
.priority(Priority.NORMAL)
.into(imageView);
设置图片大小和缩放形式
Glide 会根据ImageView的大小,自动限制图片缓存和内存中的大小,当然也可以通过调用override(horizontalSize, verticalSize)限制图片的大小:
Glide.with(context)
.load(url)
.override(200, 200)
.into(imageView);
Glide支持两种图片缩放形式,CenterCrop 和 FitCenter
CenterCrop:等比例缩放图片,直到图片的宽高都大于等于ImageView的宽度,然后截取中间的显示。
Glide
.with(context)
.load(url)
.override(200, 200)
.centerCrop()
.into(imageView);
FitCenter:等比例缩放图片,宽或者是高等于ImageView的宽或者是高
Glide
.with(context)
.load(url)
.override(200, 200)
.fitCenter()
.into(imageView);
设置监听请求接口
Glide.with(this).load(imageUrl).listener(new RequestListener<String, GlideDrawable>() {设置监听的用处 可以用于监控请求发生错误来源,以及图片来源 是内存还是磁盘
@Override
public boolean onException(Exception e, String model, Target<GlideDrawable> target, boolean isFirstResource) {
return false;
}
@Override
public boolean onResourceReady(GlideDrawable resource, String model, Target<GlideDrawable> target, boolean isFromMemoryCache, boolean isFirstResource) {
return false;
}
}).into(imageView);
Glide优化方法
清除缓存的方法
Glide.get(this).clearDiskCache();//清理磁盘缓存 需要在子线程中执行
Glide.get(this).clearMemory();//清理内存缓存 可以在UI主线程中进行
清除掉所有的图片加载请求
Glide.clear()
滚动加载,不滚动时不加载,提高listview效率,类似于滑动锁,节省流量,提高效率
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState){
case SCROLL_STATE_FLING:
Log.i("ListView","用户在手指离开屏幕之前,由于滑了一下,视图仍然依靠惯性继续滑动");
Glide.with(getApplicationContext()).pauseRequests();
//刷新
break;
case SCROLL_STATE_IDLE:
Log.i("ListView", "视图已经停止滑动");
Glide.with(getApplicationContext()).resumeRequests();
break;
case SCROLL_STATE_TOUCH_SCROLL:
Log.i("ListView","手指没有离开屏幕,视图正在滑动");
Glide.with(getApplicationContext()).resumeRequests();
break;
}
}
内存缓存
设置跳过内存缓存
Glide
.with(context)
.load(url)
.skipMemoryCache(true)
.into(imageView);
设置缓存策略(磁盘缓存)
策略解说:
all:缓存源资源和转换后的资源
none:不作任何磁盘缓存
source:缓存源资源
result:缓存转换后的资源
Glide
.with(context)
.load(url)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(imageView);
在后台线程当中进行加载和缓存
为了保证Glide在后台线程当中加载资源文件更加容易,Glide除了Glide.with(fragment).load(url).into(view)之外还提供了
downloadOnly(int width, int height)
downloadOnly(Y target)// Y extends Target<File>
into(int width, int height)
1.downloadOnly
Glide的downloadOnly()允许开发者将Image的二进制文件下载到硬盘缓存当中,以便在后续使用,
在UI线程当中异步下载,在异步线程当中则是使用width和height
在异步线程当中同步调用下载,在同步线程当中,
downloadOnly使用一个target作为参数
1、 在后台线程当中下载图片,可以通过如下的方式:
FutureTarget<File> future = Glide.with(applicationContext)
.load(yourUrl)
.downloadOnly(500, 500);
File cacheFile = future.get();
当future返回的时候,image的二进制文件信息就存入了disk缓存了,值得注意的是downloadOnly API只是保证图片个bytes数据在disk当中是有效的。
2、下载完毕之后如果想要进行显示,可以通过如下方式进行调用:
Glide.with(yourFragment)
.load(yourUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(yourView);
Glide.with(yourFragment)
.load(yourUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.into(yourView);
通过DiskCacheStrategy.ALL或者DiskCacheStrategy.SOURCE,可以保证程序会去读取缓存文件
如果想要在后台线程当中获取某个URL对应的Bitmap
不通过downloadOnly,可以使用into(),会返回一个FutureTarget对象,比如,想要得到一个URL对应的500*500的centerCrop裁剪图片,可以通过如下方式实现:
Bitmap myBitmap = Glide.with(applicationContext)
.load(yourUrl)
.asBitmap()
.centerCrop()
.into(500, 500)
.get()
大家们需要注意:上面的调用只能在异步线程当中,如果在main Thread当中调用.get(),会阻塞主线程
讲到这里有点收不住了,再给大家介绍一下,图片加载框架,picasso,Glide,Fresco(FB)的区别:
Picasso :和Square的网络库一起能发挥最大作用,因为Picasso可以选择将网络请求的缓存部分交给了okhttp实现。
Glide :模仿了Picasso的API,而且在他的基础上加了很多的扩展(比如gif等支持),Glide默认的Bitmap格式是RGB_565,比 Picasso默认的ARGB_8888格式的内存开销要小一半;Picasso缓存的是全尺寸的(只缓存一种),而Glide缓存的是跟ImageView尺寸相同的(即56*56和128*128是两个缓存) 。
FB的图片加载框架Fresco:最大的优势在于5.0以下(最低2.3)的bitmap加载。在5.0以下系统,Fresco将图片放到一个特别的内存区域(Ashmem区)。当然,在图片不显示的时候,占用的内存会自动被释放。这会使得APP更加流畅,减少因图片内存占用而引发的OOM。为什么说是5.0以下,因为在5.0以后系统默认就是存储在Ashmem区了。
总结:
Picasso所能实现的功能,Glide都能做,无非是所需的设置不同。但是Picasso体积比起Glide小太多如果项目中网络请求本身用的就是okhttp或者retrofit(本质还是okhttp),那么建议用Picasso,体积会小很多(Square全家桶的干活)。Glide的好处是大型的图片流,比如gif、Video,如果你们是做美拍、爱拍这种视频类应用,建议使用。
Fresco在5.0以下的内存优化非常好,代价就是体积也非常的大,按体积算Fresco>Glide>Picasso
不过在使用起来也有些不便(小建议:他只能用内置的一个ImageView来实现这些功能,用起来比较麻烦,我们通常是根据Fresco自己改改,直接使用他的Bitmap层)
(有不足的希望大家给我评论)