TransitionDrawable improper use causes memory leakage, transitiondrawable

Source: Internet
Author: User

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 isdisplayFirst, get the oldDrawableAnd then generate a newBitmapDrawableConstructTransitionDrawable, And finally callstartTransitionYou 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 exitActivityAfter 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 oldDrawableAs the first layer, the newDrawableCreate as Level 2TransitionDrawableBut note that we createdTransitionDrawableAnd set itImageViewThat is, we callgetDrawableYes.TransitionDrawable, OneTransitionDrawableIt actually holds multipleDrawableHere there are two.

After the program performs the first gradient animation,ImageViewInTransitionDrawableHold twoDrawable, The second gradient animation, we willTransitionDrawableNewBitmapDrawableCreate a newTransitionDrawable.
Just give a brief lookImageViewHoldDrawable:
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 wayImageViewWhich cannot be recycledDrawableThe number is increasing, and eventually OOM.

Therefore, we should not directlygetDrawableIs used as the first layer.DrawableTo determine the type of the value.TransitionDrawableThe second layer should be obtained.DrawableAs our first layer, the original first layerDrawableThe reference chain of GC Roots is lost and can be recycled.

Of course, another idea is:TransitionDrawableAfter the animation is completedBitmapDrawableSetImageViewBut there is no such listener, the simplest and most convenient is the above idea.

The final code is changed to the following, mainly to determinegetDrawableType, if it isTransitionDrawableTo 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.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.