回调
关于Target
在Glide中,Target 是介于请求和请求者之间的中介者的角色。Target 负责展示占位符,加载资源,并为每个请求决定合适的尺寸。被使用得最频繁的是 ImageViewTargets ,它用于在 ImageView 上展示占位符、Drawable 和 Bitmap 。用户还可以实现自己的 Target ,或者从任何可用的基类派生子类。
into()
之前使用Glide的时候,into()方法中都是传ImageView,查看源码可以了解到into()还有一个接收Target参数的重载方法。
1 | public <Y extends Target<TranscodeType>> Y into(@NonNull Y target) { |
其实传入ImageView,Glide内部也会自动构建一个Target对象。
1 | public Target<TranscodeType> into(ImageView view) { |
buildImageViewTarget
方法就是用来构建Target对象的。
Glide中Target的继承结构图:
![](/assets/imgs/glide_target.png)
Target的继承结构还是相当复杂的,实现Target接口的子类非常多。这些大多数都是Glide已经实现好的具备完整功能的Target子类,如果要进行自定义的话,通常只需要在两种Target的基础上去自定义就可以了,一种是SimpleTarget,一种是ViewTarget。
SimpleTarget
它是一种极为简单的Target,我们使用它可以将Glide加载出来的图片对象获取到,而不是像之前那样只能将图片在ImageView上显示出来。
SimpleTarget的用法示例,这里将获得到的加载图片的对象,进行着色:
1 | SimpleTarget<Drawable> simpleTarget = new SimpleTarget<Drawable>() { |
![](/assets/imgs/glide_05.png)
ViewTarget
跟踪buildImageViewTarget
方法,可以看出Glide在内部自动帮我们创建成
![](/assets/imgs/glide_buildtarget.png)
从上面继承机构图中可以看出,BitmapImageViewTarget和DrawableImageViewTarget就是ViewTarget的子类。只不过它们限定只能作用在ImageView上,而ViewTarget的功能更加广泛,它可以作用在任意的View上。
举个例子看下基本用法:
1、首先自定义一个MyLayout布局:
1 | public class MyLayout extends LinearLayout { |
在MyLayout的构造函数中,创建了一个ViewTarget的实例,并将Mylayout当前的实例this传了进去。ViewTarget中需要指定两个泛型,一个是View的类型,一个图片的类型(GlideDrawable或Bitmap)。然后在onResourceReady()方法中,就可以通过getView()方法获取到MyLayout的实例,并调用它的任意接口了。比如说这里我们调用了setImageAsBackground()方法来将加载出来的图片作为MyLayout布局的背景图。
2、使用ViewTarget
1 | private String url = "http://img.zcool.cn/community/0152ae56e6587c32f875520f7b9c52.jpg@1280w_1l_2o_100sh.jpg"; |
由于MyLayout中已经提供了getTarget()接口,在into()方法中传入myLayout.getTarget()即可。效果如下图所示。
![](/assets/imgs/glide_06.gif)
preload()方法
假设一个需求场景:希望提前对图片进行一个预加载,等真正需要加载图片的时候就直接从缓存中读取,不用再等待慢长的网络加载时间。
通过之前的了解知道,如果在Target对象的onResourceReady()方法中做一个空实现,也就是不做任何逻辑处理,那么图片自然也就显示不出来了,而Glide的缓存机制却仍然还会正常工作,这样不就实现预加载功能。
虽然这样同样能实现,但是比较繁琐,Glide专门给我们提供了预加载的接口,也就是preload()方法,直接使用就可以了。
1 | public Target<TranscodeType> preload(int width, int height) { |
preload()方法有两个方法重载,一个不带参数,表示将会加载图片的原始尺寸,另一个可以通过参数指定加载图片的宽和高。
preload()方法的用法也非常简单,直接使用它来替换into()方法即可,如下所示:
1 | Glide.with(this) |
需要注意的是,如果使用了preload()方法,最好要将diskCacheStrategy的缓存策略指定成DiskCacheStrategy.DATA。因为preload()方法默认是预加载的原始图片大小,而into()方法则默认会根据ImageView控件的大小来动态决定加载图片的大小。因此,如果不将diskCacheStrategy的缓存策略指定成DiskCacheStrategy.DATA的话,很容易会造成在预加载完成之后再使用into()方法加载图片,却仍然还是要从网络上去请求图片这种现象。
submit()方法
submit()方法和preload()方法类似,submit()方法也是可以替换into()方法的,这个方法只会下载图片,而不会对图片进行加载。当图片下载完成之后,我们可以得到图片的存储路径,以便后续进行操作。
同样submit()方法有两个方法重载:
- submit()
- submit(int width, int height)
其中submit()方法是用于下载原始尺寸的图片,而submit(int width, int height)则可以指定下载图片的尺寸。
使用示例:
1 | new Thread(new Runnable() { |
调用submit()方法后会返回一个FutureTarget对象,然后Glide会在后台开始下载图片文件。通过调用FutureTarget的get()方法就可以获取下载好的图片文件。
如果此时图片还没有下载完,那么get()方法就会阻塞住,一直等到图片下载完成才会有值返回,所以submit()方法必须要用在子线程当中。
这里最好使用Application Context,这个时候不能再用Activity作为Context了,因为会有Activity销毁了但子线程还没执行完这种可能出现。
效果如下
![](/assets/imgs/glide_07.gif)
监听
当需要判断图片是否加载完成,加载失败后怎么调试错误原因,这时需要设置listener()监听。
listener()
基本用法
1 | Glide.with(this) |
listener()方法中实现了一个RequestListener的实例。其中RequestListener需要实现两个方法,一个onResourceReady()方法,一个onLoadFailed()方法。当图片加载完成的时候就会回调onResourceReady()方法,而当图片加载失败的时候就会回调onLoadFailed()方法,onLoadFailed()方法中会将失败的GlideException参数传进来,这样就可以定位具体失败的原因了。
onResourceReady()方法和onLoadFailed()方法都有一个布尔值的返回值,返回false就表示这个事件没有被处理,还会继续向下传递,返回true就表示这个事件已经被处理掉了,从而不会再继续向下传递。举个简单点的例子,如果在RequestListener的onResourceReady()方法中返回了true,那么就不会再回调Target的onResourceReady()方法了。