最近要做类似网易云音乐背景高斯模糊的效果, 同时也想让背景变化时不要那么生硬, 就是下面这个效果
Google一番后决定用TransitionDrawable, 由于是配合UniversalImageLoader使用, 所以只需要实现一个BitmapDisplayer作为UIL的配置项就行了.
最初的代码是这样写的
private static class DrawableFadeDisplayer implements BitmapDisplayer {
private final int durationMillis;
public DrawableFadeDisplayer(int durationMillis) {
this.durationMillis = durationMillis;
}
@Override
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
ImageView imageview = (ImageView) imageAware.getWrappedView();
Drawable oldDrawable = imageview.getDrawable();
TransitionDrawable td = new TransitionDrawable(new Drawable[] {
oldDrawable==null?(new ColorDrawable(Color.TRANSPARENT)):oldDrawable,
new BitmapDrawable(Resources.getSystem(), bitmap)
});
imageview.setImageDrawable(td);
td.startTransition(durationMillis);
}
}
最关键的部分是display中的代码, 首先获取了旧的Drawable, 然后和新生成的BitmapDrawable一起构造一个TransitionDrawable, 最后调用startTransition就可以了.
简单明了. 实际使用中, 发现app占用的内存越来越高, 但只要退出Activity, 一两次GC之后内存就会降下来, 基本可以确定是这段代码造成了内存泄露.
问题出在这句代码
Drawable oldDrawable = imageview.getDrawable();
乍一看这句代码逻辑是没有问题的, 每次我们都是将旧的Drawable作为第一层, 新的Drawable作为第二层创建TransitionDrawable, 但是注意我们是创建的TransitionDrawable, 并将它设给ImageView, 也就是说我们调用getDrawable拿到的也是TransitionDrawable, 一个TransitionDrawable其实是持有多个Drawable的, 在这里是持有两个.
程序进行第一次渐变动画后, ImageView中的TransitionDrawable持有两个Drawable, 第二次渐变动画, 我们将TransitionDrawable和新的BitmapDrawable组合在一起创建一个新的TransitionDrawable.
简单示意一下ImageView持有的Drawable:
第一次渐变后:
TransitionDrawable(drawable0, drawable1)
第二次渐变后:
TransitionDrawable(
TransitionDrawable(drawable0, drawable1),
drawable2
)
第三次渐变后:
TransitionDrawable(
TransitionDrawable(
TransitionDrawable(drawable0, drawable1),
drawable2
),
drawable3
)
这样ImageView导致不能被回收的Drawable数量越来越多, 最终OOM.
所以我们正确的做法不应该是直接将getDrawable的值拿来当第一层Drawable, 而是先判断一下这个值的类型, 如果是TransitionDrawable, 应该获取它第二层Drawable作为我们的第一层, 这样原来的第一层Drawable就会失去到GC Roots的引用链, 从而可以被回收.
当然另一种思路是TransitionDrawable动画完成之后再将新的BitmapDrawable设给ImageView, 但并没有这个监听器, 最简单便捷的还是上面的思路.
最终代码修改成下面的样子, 主要是需要判断getDrawable的类型, 如果是TransitionDrawable, 就获取第二层Drawable.
private static class DrawableFadeDisplayer implements BitmapDisplayer {
private final int durationMillis;
public DrawableFadeDisplayer(int durationMillis) {
this.durationMillis = durationMillis;
}
@Override
public void display(Bitmap bitmap, ImageAware imageAware, LoadedFrom loadedFrom) {
ImageView imageview = (ImageView) imageAware.getWrappedView();
Drawable oldDrawable = imageview.getDrawable();
Drawable oldBitmapDrawable = null;
if (oldDrawable == null) {
oldBitmapDrawable = new ColorDrawable(Color.TRANSPARENT);
} else if (oldDrawable instanceof TransitionDrawable) {
oldBitmapDrawable = ((TransitionDrawable) oldDrawable).getDrawable(1);
} else {
oldBitmapDrawable = oldDrawable;
}
TransitionDrawable td = new TransitionDrawable(new Drawable[] {
oldBitmapDrawable,
new BitmapDrawable(Resources.getSystem(), bitmap)
});
imageview.setImageDrawable(td);
td.startTransition(durationMillis);
}
}版权声明:本文为博主原创文章,未经博主允许不得转载。
原文:http://blog.csdn.net/shaw1994/article/details/46846075