Glide 中的回调:Targets
目前为止,我们很方便的使用 Glide 建造者去加载图片到 ImageView 中了。Glide 隐藏了一大堆复杂的在后台的场景。Glide 做了所有的网络请求和处理在后台线程中,一旦结果准备好了之后,切回到 UI 线程然后更新 ImageView。
在这篇博客中,我们假定 ImageView 不再是图像的最后一步。我们只要 Bitmap 本身。Glide 提供了一个用 Targets 的简单的方式去接受图片资源的 Bitmap。Targets 是回调函数,它在 Glide 做完所有的加载和处理之后返回结果。
Glide 提供了各种的 targets 并且每个都有其明确的目的。我们将在接下来的几节中通过使用它们。让我们从 SimpleTarget 开始。
SimpleTarget
看如下代码实例:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> SimpleTarget target = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> SimpleTarget<Bitmap>() {
@Override
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onResourceReady</span>(Bitmap bitmap, GlideAnimation glideAnimation) {
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// do something with the bitmap</span>
<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// for demonstration purposes, let's just set it to an ImageView</span>
imageView1.setImageBitmap( bitmap );
}
};
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loadImageSimpleTarget</span>() {
Glide
.with( context ) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// could be an issue!</span>
.load( eatFoodyImages[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>] )
.asBitmap()
.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">into</span>( target );
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li></ul>
这段代码的第一部分创建了一个字段对象,声明了一个方法,即一旦 Glide 已加载并处理完图像,它将被调用。这个回调方法传了 Bitmap 作为一个参数。你之后便可以使用这个 Bitmap 对象,无论你要怎样用它。
这段代码的第二部分是我们如何通过 Glide 用 targets:和 ImageView 用法完全相同的!你既可以传一个 Target 也可以传一个 ImageView 参数给.into() 方法。Glide 自己将会处理并返回结果给任何一个。这里有一些不同的是,我们添加了 .asBitmap(),它强制 Glide 去返回一个 Bitmap 对象。记住,Glide 也可以加载 Gif 或 video 的。为了防止 target 的冲突(我们需要 Bitmap) 和未知资源在网络背后的 URL(可能是一个 Gif),我们可以调用 .asBitmap() 告诉 Glide 我们需要一个图像。
关注 Targets
除了知道如何实现一个简单版本的 Glide 的 Target 回调系统,你要学会额外两件事。
-
首先是 SimpleTarget 对象的字段声明。从技术上来说,Java/Android 会允许你在 .into() 方法中去声明 target 的匿名内部类。然而,这大大增加了这样一个可能性:即在 Glide 做完图片请求之前, Android 垃圾回收移除了这个匿名内部类对象。最终这可能会导致一个情况,当图像加载完成了,但是回调再也不会被调用。所请确保你所声明的回调对象是作为一个字段对象的,这样你就可以保护它避免被邪恶的 Android 垃圾回收机制回收 ;
-
第二个关键部分是 Glide 建造者中这行:.with(context)。 这里的问题实际是 Glide 的功能:当你传了一个 context(例如是当前应用的 activity),Glide 将会自动停止请求当 activity 已经停止的时候。这整合到了应用的生命周期中通常是非常有帮助的,但是有时工作起来是困难的,如果你的 target 是独立于应用的 activity 生命周期。这里的解决方案是用 application 的 context: .with(context.getApplicationContext))。当应用资深完全停止时,Glide 才会杀死这个图片请求。请求记住,再说一次,如果你的请求需要在 activity 生命周期之外去做时,才用下面这样的代码:
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loadImageSimpleTargetApplicationContext</span>() {
Glide
.with( context.getApplicationContext() ) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// safer!</span>
.load( eatFoodyImages[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>]
.asBitmap()
.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">into</span>( target2 );
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>
Target 指定尺寸
另一个潜在的问题是,target 没有指明大小。如果你传一个 ImageView 作为参数给 .into(),Glide 将会用 ImageView 的大小去限制图像的大小。比如说,如果加载的图片是 1000x1000 像素的,但是 ImageView 只有 250x250 像素,Glide 将会减少图片的尺寸去节省时间和内存。很显然,在和 target 协作的时候并没有这么做,因为我们并没有已知的大小。然而,如果你有一个指定的大小,你可以加强回调。如果你知道这种图片应该要多大,你应该在你的回调声明中指定它以节省一些内存。
<code class="hljs cs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> SimpleTarget target2 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> SimpleTarget<Bitmap>( <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">250</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">250</span> ) {
@Override
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onResourceReady</span>(Bitmap bitmap, GlideAnimation glideAnimation) {
imageView2.setImageBitmap( bitmap );
}
};
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loadImageSimpleTargetApplicationContext</span>() {
Glide
.with( context.getApplicationContext() ) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// safer!</span>
.load( eatFoodyImages[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>] )
.asBitmap()
.<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">into</span>( target2 );
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>
ViewTarget
我们不能直接使用 ImageView 的原因可能是多种多样的。我们已经向你展示如何去接收一个 Bitmap。现在我们要更进一步。假设你有一个 Custom View。Glide 并不支持加载图片到自定义 view 中,因为并没有方法知道图片应该在哪里被设置。然而,Glide 可以用 ViewTarget 更容易实现。
让我们看一个简单的自定义 View,它继承自 FrameLayout 并内部使用了一个 ImageView 以及覆盖了一个 TextView。
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">FutureStudioView</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">FrameLayout</span> {</span>
ImageView iv;
TextView tv;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">initialize</span>(Context context) {
inflate( context, R.layout.custom_view_futurestudio, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span> );
iv = (ImageView) findViewById( R.id.custom_view_image );
tv = (TextView) findViewById( R.id.custom_view_text );
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">FutureStudioView</span>(Context context, AttributeSet attrs) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>( context, attrs );
initialize( context );
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">FutureStudioView</span>(Context context, AttributeSet attrs, <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> defStyleAttr) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>( context, attrs, defStyleAttr );
initialize( context );
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">setImage</span>(Drawable drawable) {
iv = (ImageView) findViewById( R.id.custom_view_image );
iv.setImageDrawable( drawable );
}
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li><li style="box-sizing: border-box; padding: 0px 5px;">24</li><li style="box-sizing: border-box; padding: 0px 5px;">25</li><li style="box-sizing: border-box; padding: 0px 5px;">26</li><li style="box-sizing: border-box; padding: 0px 5px;">27</li></ul>
你不能使用常规的 Glide 的方法 .into(),因为我们的自定义 view 并不继承自 ImageView。因此,我们必须创建一个 ViewTarget,并用 .into() 方法:
<code class="hljs java has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">loadImageViewTarget</span>() {
FutureStudioView customView = (FutureStudioView) findViewById( R.id.custom_view );
viewTarget = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ViewTarget<FutureStudioView, GlideDrawable>( customView ) {
<span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onResourceReady</span>(GlideDrawable resource, GlideAnimation<? <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span> GlideDrawable> glideAnimation) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.view.setImage( resource.getCurrent() );
}
};
Glide
.with( context.getApplicationContext() ) <span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">// safer!</span>
.load( eatFoodyImages[<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">2</span>] )
.into( viewTarget );
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>
在 target 回调方法中,我们使用我们创建的方法 setImage(Drawable drawable)
在自定义 view 类中去设置图片。另外确保你注意到我们必须在ViewTarget 的构造函数中传递我们自定义 view 作为参数:new ViewTarget<FutureStudioView, GlideDrawable>(customView)
。
这应该涵盖了所有你需要的自定义 view。你也可以在回调中添加额外的工作。如,我们可以分析传入的 Bitmap 的主要的颜色并设置十六进制值给 TextView。但我们相信你应该已经有一些想法了。
转自:http://blog.csdn.net/xx326664162/article/details/50964414
Android学习交流群:523487222