一、glide的基本使用
(1)导入库
dependencies {
compile 'com.github.bumptech.glide:glide:3.6.1'
}
(2)使用
Glide.with(context)
.load("http://inthecheesefactory.com/uploads/source/glidepicasso/cover.jpg")
.into(ivImg);
二、分析
(一)Glide.with(……)
我们来看一下Gilde的源码
/**
* Begin a load with Glide by passing in a context.
*
* <p>
* Any requests started using a context will only have the application level options applied and will not be
* started or stopped based on lifecycle events. In general, loads should be started at the level the result
* will be used in. If the resource will be used in a view in a child fragment,
* the load should be started with {@link #with(android.app.Fragment)}} using that child fragment. Similarly,
* if the resource will be used in a view in the parent fragment, the load should be started with
* {@link #with(android.app.Fragment)} using the parent fragment. In the same vein, if the resource will be used
* in a view in an activity, the load should be started with {@link #with(android.app.Activity)}}.
* </p>
*
* <p>
* This method is appropriate for resources that will be used outside of the normal fragment or activity
* lifecycle (For example in services, or for notification thumbnails).
* </p>
*
* @see #with(android.app.Activity)
* @see #with(android.app.Fragment)
* @see #with(android.support.v4.app.Fragment)
* @see #with(android.support.v4.app.FragmentActivity)
*
* @param context Any context, will not be retained.
* @return A RequestManager for the top level application that can be used to start a load.
*/
public static RequestManager with(Context context) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(context);
}
/**
* Begin a load with Glide that will be tied to the given {@link android.app.Activity}'s lifecycle and that uses the
* given {@link Activity}'s default options.
*
* @param activity The activity to use.
* @return A RequestManager for the given activity that can be used to start a load.
*/
public static RequestManager with(Activity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
/**
* Begin a load with Glide that will tied to the give {@link android.support.v4.app.FragmentActivity}'s lifecycle
* and that uses the given {@link android.support.v4.app.FragmentActivity}'s default options.
*
* @param activity The activity to use.
* @return A RequestManager for the given FragmentActivity that can be used to start a load.
*/
public static RequestManager with(FragmentActivity activity) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(activity);
}
/**
* Begin a load with Glide that will be tied to the given {@link android.app.Fragment}'s lifecycle and that uses
* the given {@link android.app.Fragment}'s default options.
*
* @param fragment The fragment to use.
* @return A RequestManager for the given Fragment that can be used to start a load.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static RequestManager with(android.app.Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
/**
* Begin a load with Glide that will be tied to the given {@link android.support.v4.app.Fragment}'s lifecycle and
* that uses the given {@link android.support.v4.app.Fragment}'s default options.
*
* @param fragment The fragment to use.
* @return A RequestManager for the given Fragment that can be used to start a load.
*/
public static RequestManager with(Fragment fragment) {
RequestManagerRetriever retriever = RequestManagerRetriever.get();
return retriever.get(fragment);
}
**总结:可以传入的参数有
*@see #with(android.app.Activity)
* @see #with(android.app.Fragment)
* @see #with(android.support.v4.app.Fragment)
* @see #with(android.support.v4.app.FragmentActivity)
同时将Activity/Fragment作为with()参数的好处是:图片加载会和Activity/Fragment的生命周期保持一致,比如Paused状态在暂停加载,在Resumed的时候又自动重新加载。所以我建议传参的时候传递Activity 和 Fragment给Glide,而不是Context。****
(二)占位符使用
如果要使用Gilde显示一张网络上的图片,当网络不好的时候加载图片可能需要很长的时间,一个空的ImageViewzai 在任何UI上都不好看,这就有了占位符,在图片加载完成以前显示占位符。
Glide 的流式接口让这个变得非常容易的去做到!只需要调用 .placeHolder() 用一个 drawable(resource) 引用,Glide 将会显示它作为一个占位符,直到你的实际图片准备好。
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.into(imageViewPlaceholder);
总结:1.你不能设置一个网络 url 作为占位符,因为这也会被去请求加载的。
2.load()里面,Glide接受所有的值(可以是本地的资源也可以是网络上的资源)。
(三)错误占位符
可以从字面的意思来理解什么是错误的占位符,也就是我们的APP从一个网站去加载一张图片的时候,返回时告诉我们获取失败,这时就用到了错误占位符来显示图片,如果想进行一些其他操作,可自己决定。
调用 Glide 的流式接口和之前显示预加载占位符的例子是相同的,不同的是调用了名为 error() 的函数。
Glide
.with(context)
.load("http://futurestud.io/non_existing_image.png")
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.error(R.mipmap.future_studio_launcher) // will be displayed if the image cannot be loaded
.into(imageViewError);
就这样。如果你定义的 load() 值的图片不能被加载出来,Glide 会显示 R.mipmap.future_studio_launcher 作为替换。再说一次,error()接受的参数只能是已经初始化的 drawable 对象或者指明它的资源(R.drawable.)。
(四)使用 crossFade()
无论你是在加载图片之前是否显示一个占位符,改变 ImageView 的图片在你的 UI 中有非常显著的变化。一个简单的选项是让它改变是更加平滑和养眼的,就是使用一个淡入淡出动画。Glide 使用标准的淡入淡出动画,这是(对于当前版本3.6.1)默认激活的。如果你想要如强制 Glide 显示一个淡入淡出动画,你必须调用另外一个建造者:
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.error(R.mipmap.future_studio_launcher) // will be displayed if the image cannot be loaded
.crossFade()
.into(imageViewFade);
crossFade() 方法还有另外重载方法 .crossFade(int duration)。如果你想要去减慢(或加快)动画,随时可以传一个毫秒的时间给这个方法。动画默认的持续时间是 300毫秒。
(五)使用 dontAnimate()
如果你想直接显示图片而没有任何淡入淡出效果,在 Glide 的建造者中调用 .dontAnimate() 。
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.placeholder(R.mipmap.ic_launcher) // can also be a drawable
.error(R.mipmap.future_studio_launcher) // will be displayed if the image cannot be loaded
.dontAnimate()
.into(imageViewFade);
这是直接显示你的图片,而不是淡入显示到 ImageView。请确保你有更好的理由来做这件事情。
需要知道的是所有这些参数都是独立的,而不需要彼此依赖的。比如,你可以设定 .error() 而不调用 .placeholder()。你可能设置 crossFade() 动画而没有占位符。任何参数的组合都是可能的。
(六)用 override(horizontalSize, verticalSize) 调整图片大小
在和 Picasso 比较后,Glide 有更加高效的内存管理。Glide 自动限制了图片的尺寸在缓存和内存中,并给到 ImageView 需要的尺寸。对于 Glide,如果图片不会自动适配到 ImageView,调用 override(horizontalSize, verticalSize) 。这将在图片显示到 ImageView之前重新改变图片大小。
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200) // resizes the image to these dimensions (in pixel). does not respect aspect ratio
.into(imageViewResize);
总结:对于上面的例子来看,在没有显示图片之前图片的大小为600*200.
(七)缩放图像
现在,对于任何图像操作,调整大小真的能让长宽比失真并且丑化图像显示。在你大多数的使用场景中,你想要避免发生这种情况。Glide 提供了一般变化去处理图像显示。提供了两个标准选项:centerCrop 和 fitCenter。
CenterCrop
CenterCrop()是一个裁剪技术,即缩放图像让它填充到 ImageView 界限内并且侧键额外的部分。ImageView 可能会完全填充,但图像可能不会完整显示。
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200) // resizes the image to these dimensions (in pixel)
.centerCrop() // this cropping technique scales the image so that it fills the requested bounds and then crops the extra.
.into(imageViewResizeCenterCrop);
FitCenter
fitCenter() 是裁剪技术,即缩放图像让图像都测量出来等于或小于 ImageView 的边界范围。该图像将会完全显示,但可能不会填满整个 ImageView。
Glide
.with(context)
.load(UsageExampleListViewAdapter.eatFoodyImages[0])
.override(600, 200)
.fitCenter()
.into(imageViewResizeFitCenter);
总结:平时在使用的时候还是CenterCrop()的时候多一些。大家也知道ImageView里面也会用到android:scaleType=”centerCrop”,可以去对比一下。
(八)内存缓存
让我们想象一个非常简单的请求,从网络中加载图片到 ImageView。
Glide
.with( context )
.load( eatFoodyImages[0] )
.skipMemoryCache( true )
.into( imageViewInternet );
你已经注意到,我们调用了 .skipMemoryCache(true) 去明确告诉 Glide 跳过内存缓存。这意味着 Glide 将不会把这张图片放到内存缓存中去。这里需要明白的是,这只是会影响内存缓存!Glide 将会仍然利用磁盘缓存来避免重复的网络请求。
这也容易知道 Glide 将会默认将所有的图片资源放到内存缓存中去。因为,指明调用 .skipMemoryCache(false) 是没有必要的。
提示:注意个事实,如果你的一个初始请求一个但是 URL 是相同的,但没有调用 .skipMemoryCache(true) ,然后你后来又调用了这个方法,这是这个资源将会在内存中获取缓存。当你想要去调整缓存行为时,确保你是要调用所有相同资源的时候。
(九)跳过磁盘缓存
正如你上面这部分所了解到的,即使你关闭内存缓存,请求图片将会仍然被存储在设备的磁盘缓存中。如果你有一张图片具有相同的 URL,但是变化很快,你可能想要连磁盘缓存也一起禁用。
源码:
/**
* {@inheritDoc}
*/
@Override
public DrawableRequestBuilder<ModelType> diskCacheStrategy(DiskCacheStrategy strategy) {
super.diskCacheStrategy(strategy);
return this;
}
你可以用 .diskCacheStrategy() 方法为 Glide 改变磁盘缓存的行为。不同的于 .skipMemoryCache() 方法,它需要一个枚举而不是一个简答的布尔值。如果你想要为一个请求禁用磁盘缓存。使用枚举 DiskCacheStrategy.NONE 作为参数。
Glide
.with( context )
.load( eatFoodyImages[0] )
.diskCacheStrategy( DiskCacheStrategy.NONE )
.into( imageViewInternet );
图片在这段代码片段中将不会被保存在磁盘缓存中。然而,默认的它将仍然使用内存缓存!为了把这里两者都禁用掉,两个方法一起调用:
Glide
.with( context )
.load( eatFoodyImages[0] )
.diskCacheStrategy( DiskCacheStrategy.NONE )
.skipMemoryCache( true )
.into( imageViewInternet );
(十)图片请求的优先级
通常,你会遇到这样的使用场景:你的 App 将会需要在同一时间内加载多个图像。让我们假设你正在构建一个信息屏幕,这里有一张很大的英雄图片在顶部,还有两个小的,在底部还有一些不那么重要的图片。对于最好的用户体验来说,应用图片元素是显示要被加载和显示的,然后才是底部不紧急的 ImageView。Glide 可以用 Priority 枚举来支持你这样的行为,调用 .priority() 方法。
但在看这个方法调用的示例代码之前,让么我看看 priority 的枚举值,它首先作为 .priority() 方法的参数的。
了解 Priority (优先级)枚举
这个枚举给了四个不同的选项,下面是按照递增priority(优先级)的列表:
Priority.LOW
Priority.NORMAL
Priority.HIGH
Priority.IMMEDIATE
在我们开始例子前,你应该知道的是:优先级并不是完全严格遵守的。Glide 将会用他们作为一个准则,并尽可能的处理这些请求,但是它不能保证所有的图片都会按照所要求的顺序加载。
然而,如果你有的使用场景是确定一些图片是重要的,充分利用它!
使用实例:英雄元素和子图像
让我们开始回到开始时的例子吧。你正在实现一个信息详情页面,有一个英雄图片在顶部,和较小的图片在底部。对于最好的用户体验来说,英雄图片首先需要被加载。因此,我们用 Priority.HIGH 来处理它。理论上说,这应该够了,但是为了让这个实例增加点趣味,我们也将底层图像分配给低优先级,用 .priority(Priority.LOW) 调用:
private void loadImageWithHighPriority() {
Glide
.with( context )
.load( UsageExampleListViewAdapter.eatFoodyImages[0] )
.priority( Priority.HIGH )
.into( imageViewHero );
}
private void loadImagesWithLowPriority() {
Glide
.with( context )
.load( UsageExampleListViewAdapter.eatFoodyImages[1] )
.priority( Priority.LOW )
.into( imageViewLowPrioLeft );
Glide
.with( context )
.load( UsageExampleListViewAdapter.eatFoodyImages[2] )
.priority( Priority.LOW )
.into( imageViewLowPrioRight );
}
如果你运行这个实例,你会看到,在几乎所有的情况下,英雄图片将会首先显示出来。尽管是更大的图像(因为需要更多的处理时间)。