TransitionDrawable improper use causes memory leakage, transitiondrawable
Recently, I want to make a blur effect similar to that of Netease cloud music background. I also want to make the background changes not so stiff, that is, the following effect.
Google decided to use TransitionDrawable. Because it was used with UniversalImageLoader, you only need to implement a BitmapDisplayer as the UIL configuration item.
The original code was written in this way.
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); }}
The most important part isdisplay
First, get the oldDrawable
And then generate a newBitmapDrawable
ConstructTransitionDrawable
, And finally callstartTransition
You can.
Simple and clear. In actual use, it is found that the memory occupied by the app is getting higher and higher, but you only need to exitActivity
After one or two GC operations, the memory will be reduced. It can be confirmed that this code has caused Memory leakage.
The problem lies in this Code.
Drawable oldDrawable = imageview.getDrawable();
At first glance, there is no problem with the code logic. Every time we change the oldDrawable
As the first layer, the newDrawable
Create as Level 2TransitionDrawable
But note that we createdTransitionDrawable
And set itImageView
That is, we callgetDrawable
Yes.TransitionDrawable
, OneTransitionDrawable
It actually holds multipleDrawable
Here there are two.
After the program performs the first gradient animation,ImageView
InTransitionDrawable
Hold twoDrawable
, The second gradient animation, we willTransitionDrawable
NewBitmapDrawable
Create a newTransitionDrawable
.
Just give a brief lookImageView
HoldDrawable
:
After the first gradient:
TransitionDrawable(drawable0, drawable1)
After the second gradient:
TransitionDrawable( TransitionDrawable(drawable0, drawable1), drawable2)
After the third gradient:
TransitionDrawable( TransitionDrawable( TransitionDrawable(drawable0, drawable1), drawable2 ), drawable3)
This wayImageView
Which cannot be recycledDrawable
The number is increasing, and eventually OOM.
Therefore, we should not directlygetDrawable
Is used as the first layer.Drawable
To determine the type of the value.TransitionDrawable
The second layer should be obtained.Drawable
As our first layer, the original first layerDrawable
The reference chain of GC Roots is lost and can be recycled.
Of course, another idea is:TransitionDrawable
After the animation is completedBitmapDrawable
SetImageView
But there is no such listener, the simplest and most convenient is the above idea.
The final code is changed to the following, mainly to determinegetDrawable
Type, if it isTransitionDrawable
To obtain the second layer.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); }}
Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.