前言
系列文章专栏: 玩转Glide4
基础使用篇:Android 玩转Glide4—基础使用篇
进阶使用篇:Android 玩转Glide4—进阶使用篇
Transformation篇:Android 玩转Glide4—Transformation篇
概述
基础使用篇中我们简单介绍了Glide4的使用,以及相对于Glide3的变化。
本篇进阶篇,将会介绍预加载,生命周期,加载监听,下载图片等方面的内容。
预加载—preload()
Glide加载图片会自动判断图片是否在缓存中,以此来决定直接读取缓存还是直接下载。
但是如果我希望提前对图片进行一个预加载,比如有一张网络大图,进入页面最开始不需要展示,但是需要展示的时候我们想立刻展示出来,而不需要等待。
怎么办呢?----可以使用preload()方法。
public Target<TranscodeType> preload(int width, int height) //指定加载图片的宽和高
public Target<TranscodeType> preload() //加载图片的原始尺寸
preload()方法的用法非常简单,直接使用它来替换into()方法即可,如下代码:
Glide.with(this)
.load(ConstUrl.ImgGif)
.preload()
我们可以在页面打开的时候先preload()预加载,然后需要显示的into()接口,如下代码:
preload.setOnClickListener {
Glide.with(this)
.load(ConstUrl.ImgGif)
.into(ivPreload)
}
加载监听—listener()
如果一张网络图片未按照预期中显示出来,我们就需要知道它的加载状态。listener()用来监听Glide加载图片的状态失败还是完成。
Glide.with(this).load(ConstUrl.ImgOne).listener(object : RequestListener<Drawable> {
override fun onLoadFailed(e: GlideException?, model: Any?, target: Target<Drawable>?, isFirstResource: Boolean): Boolean {
Log.e(TAG, "onLoadFailed", e)
return false
}
override fun onResourceReady(resource: Drawable?, model: Any?, target: Target<Drawable>?, dataSource: DataSource?, isFirstResource: Boolean): Boolean {
Log.i(TAG, "onResourceReady")
resource.to
return false
}
}).into(ivListener)
不过还有一点需要处理,onResourceReady()方法和onLoadFailed()方法都有一个布尔值的返回值,返回false就表示这个事件没有被处理,还会继续向下传递,返回true就表示这个事件已经被处理掉了,从而不会再继续向下传递。
图片下载—submit()
如果没有图片框架的帮助下我们去显示一张网络图片,通常的做法都是异步线程下载字节流保存到本地为File,然后再显示这个File。
对于Glide来说,将图片保存在本地有很多中方法,比如上面的listener方法的onResourceReady回调中,我们可以拿到Drawable.toBitmap()转为Bitmap对象,然后再转为字节流存在File中。
然而Glide给我们提供了一个更加便捷的方法submit()。
相对与preload(),submit()只会下载图片,不会加载,也不会缓存图片,需要我们拿到下载完成图片文件自己去操作。
public FutureTarget<TranscodeType> submit() //下载原始尺寸的图片
public FutureTarget<TranscodeType> submit(int width, int height) //指定下载图片的尺寸
调用了submit()方法后会返回一个FutureTarget对象,然后Glide会在后台开始下载图片。接下来需要我们调用FutureTarget的get()方法去获取下载图片文件,如果此时图片还没有下载完,那么get()方法就会阻塞住,一直等到图片下载完成才会有值返回。
因此submit()必须在异步线程中执行,代码如下:
download.setOnClickListener {
Thread(Runnable {
val taget = Glide.with(this).asFile().load(ConstUrl.ImgOne).submit()
val imgFile = taget.get()
runOnUiThread {
Glide.with(this).load(imgFile).into(ivDownload)
Toast.makeText(this, imgFile.path, Toast.LENGTH_LONG).show()
}
}).start()
}
生命周期—Target
Gilde的into()方法,通常我们都是传ImageView的,但是查看源码就知道它还能传Target类型的参数。
你会发现Target中有两个重写函数onResourceReady,onLoadFailed跟listener很相似,实际上他们的作用也几乎一致,那么他们的区别是什么呢?
你可以理解Target中的这两个函数为listener中分发函数,主要便于我们自定义Target时使用。
分发体现在:如果我们在RequestListener的onResourceReady()方法中返回了true,那么就不会再回调Target的onResourceReady()方法了。
DrawableImageViewTarget
Gilde4中封装好了一些ViewTarget,我们可以很方便的调用,我们以DrawableImageViewTarget为例子。
比如我们需要在加载图片的时候先显示一个进度条,加载完成后进度条消失,代码如下
val simpleTarget = object : DrawableImageViewTarget(ivInto) {
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
super.onResourceReady(resource, transition)
progressBar.hide()
}
override fun onLoadStarted(placeholder: Drawable?) {
super.onLoadStarted(placeholder)
progressBar.show()
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
}
override fun onLoadCleared(placeholder: Drawable?) {
super.onLoadCleared(placeholder)
}
override fun onStart() {
super.onStart()
}
override fun onStop() {
super.onStop()
}
override fun onDestroy() {
super.onDestroy()
}
}
val optionInto = RequestOptions()
.skipMemoryCache(true)
.diskCacheStrategy(DiskCacheStrategy.NONE)
Glide.with(this).load(ConstUrl.ImgGif).apply(optionInto).into(simpleTarget)
自定义Target—CustomViewTarget
我们可以让Glide加载出来的图片不显示到ImageView上吗?答案是肯定的,这就需要用到自定义Target功能。
我们简单实现如下布局控件,我们要在左边显示网路图片,右边显示ic_launcher。代码如下:
<LinearLayout
android:id="@+id/targetLayout"
android:layout_width="match_parent"
android:layout_height="200dp"
app:layout_constraintStart_toStartOf="@id/ivInto"
app:layout_constraintTop_toBottomOf="@id/ivInto">
<ImageView
android:id="@+id/iv1"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<ImageView
android:id="@+id/iv2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:src="@mipmap/ic_launcher" />
</LinearLayout>
class MyTarget constructor(view: View) : CustomViewTarget<View, Drawable>(view) {
override fun onLoadFailed(errorDrawable: Drawable?) {
}
override fun onResourceCleared(placeholder: Drawable?) {
}
override fun onResourceReady(resource: Drawable, transition: Transition<in Drawable>?) {
view.findViewById<ImageView>(R.id.iv1).setImageDrawable(resource)
}
}
Glide.with(this).load(ConstUrl.ImgOne).apply(optionInto).into(MyTarget(targetLayout))
Glide组件—GlideModule
由于Glide内部网络加载使用的是HttpURLConnection
,相较我们经常使用的Okhttp性能上差距较大,因此我们经常会使用Okhttp替换网络组件。
4.x的自定义组件相较于3.x改动较大:
- 自定义模块类上使用注解即会自动注册,可以不用通过Manifest注册。
- 在应用模块中需要继承
AppGlideModule
实现,在中则必须要继承LibraryGlideModule
实现,而非3.x的GlideModule
。 - 注册调用replace方法的类改成了Registry而非Glide。
如我们实现一个Okhhtp网络组件。
1.引入Okhttp依赖和Glide官方的Okhttp集成库。
//okhttp3
implementation 'com.squareup.okhttp3:okhttp:4.7.2'
//Glide官方扩展库,https://github.com/bumptech/glide/tree/master/integration/okhttp3
implementation 'com.github.bumptech.glide:okhttp3-integration:4.3.1'
2.应用模块中继承AppGlideModule
实现。
@GlideModule
class GlideConfigModule :AppGlideModule() {
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
//super.registerComponents(context, glide, registry)
registry.replace(GlideUrl::class.java, InputStream::class.java, OkHttpUrlLoader.Factory())
}
}
实际上官方的Okhttp集成库,已经实现了上面的代码OkHttpLibraryGlideModule,我们只需要引入依赖即可。
@GlideModule
public final class OkHttpLibraryGlideModule extends LibraryGlideModule {
@Override
public void registerComponents(
@NonNull Context context, @NonNull Glide glide, @NonNull Registry registry) {
registry.replace(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory());
}
}
代码
GitHub: https://github.com/DeMonDemo/Glide4Img