目前为止,我们总是假设加载图片或Gif到ImageView上,但那并不适用所有的情况。本文将要介绍在没有指定的ImageView时,获取一个图片的资源。
我们已经能够很方便地使用Glide去加载图片到ImageView中。在应用场景中,Glide隐藏了大量复杂的工作。Glide在后台线程中处理了所有的网络请求,一旦结果准备完毕,就会调用UI线程更新ImageVIew。
假设我们并没有ImageView作为图片加载的目标。我们只需要Bitmap本身。Glide提供了一个用Target获取Bitmap资源的方法。Target只是用来回调,它会在所有的加载和处理完毕时返回想要的结果。
Glide提供了多种多样有各自明确目的Target。我们先从SimpleTarget介绍。
SimpleTarget
代码如下:
1 | private SimpleTarget target = new SimpleTarget<Bitmap>() { |
代码的第一部分,创建一个target字段对象,里面定义了个方法,这个方法一旦Glide加载和处理完图片将会被调用。回调方法传回Bitmap作为参数,你可以在你所需要用的地方随意使用这个Bitmap对象。
代码的第二部分,表明了Glide里如何使用Target,明显跟ImageView一样。你可以传递一个Target或者ImageView作为参数到.into()方法里。Glide会将结果返回。这里有个不同点,我们添加了.asBitmap(),这会强制返回一个Bitmap对象。记住,Glide也可以加载Gif或视频。为了防止在从网络URL(可能是GIF)获取Bitmap时,出现未知格式图片冲突(期望是Bitmap),我们设置.asBitmap()去告诉Glide只有在资源是一个图片是才算成功,其它的都算解析失败。
使用Target注意事项
第一个是SimpleTarget对象的定义。java/Android可以允许你在.into()内匿名定义,但这会显著增加在Glide处理完图片请求前Android垃圾回收清理匿名target对象的可能性。最终,会导致图片被加载了,但是回调永远不会被调用。所以,请确保将你的回调定义为一个字段对象,防止被Android垃圾回收给清理掉。
第二个关键部分是Glide的.with( context )。这个问题实际上是Glide一个特性问题:当你传递了一个context,例如当前app的activity,当activity停止后,Glide会自动停止当前的请求。这种整合到app生命周期内是非常有用的,但也是很难处理的。如果你的target是独立于app的生命周期。这里的解决方案是使用application的context:.with( context.getApplicationContext() )。当app自己停止运行的时候,Glide会只取消掉图片的请求。请记住,再次提醒,如果你的请求需要在activity的生命周期以外,使用下面的代码:
1 | private void loadImageSimpleTargetApplicationContext() { |
特定大小的Target
另外一个潜在问题是Target没有一个明确的大小。如果你传递一个ImageView作为.into()的参数,Glide会使用ImageView的大小来限制图片的大小。如果要加载的图片是1000x1000像素,但是ImageView的尺寸只有250x250像素,Glide会降低图片到小尺寸,以节省处理时间和内存。显然,由于target没有具体大小,这对target并不起效。但是,如果你有个期望的具体大小,你可以增强回调。如果你知道图片应当为多大,那么在你的回调定义里应当指明,以节省内存:
1 | private SimpleTarget target2 = new SimpleTarget<Bitmap>( 250, 250 ) { |
和“普通”target唯一不同的是这个以像素为单位的图片大小声明:new SimpleTarget
ViewTarget
有很多原因导致我们不能直接使用ImageView。前面已经介绍了如何获取Bitmap。假设你有个自定义的View,由于没有已知的方法在哪里设置图片,Glide并不支持加载图片到定制的View内。然而用ViewTarget会让这个问题更简单。
先看一个简单的定制View,它继承于FrameLayout,内部使用了一个ImageView,上面覆盖了一个TextView:
1 | public class FutureStudioView extends FrameLayout { |
由于我们定制的view并不是继承自ImageView,这里不能使用常规的.into()方法。因此,我们只能创建一个ViewTarget,用来传递给.into()方法:
1 | private void loadImageViewTarget() { |
在target的回调方法中,我们在定制view上使用我们创建的setImage(Drawable drawable)方法设置图片。同时,确保已经在ViewTarget的构造方法里传递了定制view:new ViewTarget<FutureStudioView, GlideDrawable>( customView )。
这应该覆盖了所有可能需要定制的view。你也可以在回调中做额外的工作。例如,我们可以解析即将到来的图片的主色调,然后设置TextView的颜色。
参考资料:
签到钱就到 Glide入门教程——10. 回调:定制view中使用SimpleTarget和ViewTarget