Android内存优化- 方式十二: Animator的使用与释放(Android 内存泄漏)

时间:2024-06-01 10:09:32

Android 内存泄漏 - Animator的使用与释放
在属性动画中如果定义为无限循环,如果在Activity中播放这类动画并且在其退出(生命周期结果前)未停止动画,造成内存泄漏。
举例说明
假设有如下无限循环动画:

public class LeakActivity extends AppCompatActivity {
    private TextView textView;
    private ValueAnimator warningAnimation;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_leak);
        textView = (TextView)findViewById(R.id.text_view);
        warningAnimation.setDuration(1000);
            warningAnimation.setRepeatMode(ValueAnimator.REVERSE);
            //定义为无线循环动画
            warningAnimation.setRepeatCount(ValueAnimator.INFINITE);
            warningAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animator) {
                    textView.setBackgroundColor((int) animator.getAnimatedValue());
                }
            });
    }
}

但是在符合某一条件但是没有满足(或者根本没有对该动画进行停止)即退出该LeakActivity.
解决方法
确保Animator.cancel() 能够在Activity退出时被执行到(尤其留意是否存在条件判断)。
源码分析泄漏原因
那么为什么不对Animator动画做取消动作,就会出现内存泄漏呢?
看到Animator中的cancel函数的源码:
Android内存优化- 方式十二: Animator的使用与释放(Android 内存泄漏)

从源码中可以看出:cancel函数会针对AnimatorSet中所有的自动化逐个进行释放。
继续看endAnimation()函数:

Android内存优化- 方式十二: Animator的使用与释放(Android 内存泄漏)Android内存优化- 方式十二: Animator的使用与释放(Android 内存泄漏)
可以从源码中看出,确实是通过单例实现的,因此Animator的引用实际上在未调用cancel()/end()之前,如果该动画是无限循环,即自身不会主动结束释放,那么是一直被静态变量sAnimatorHandler所持有的,导致即使Activity退出,此块Animator的内存始终无法被回收。

Android-内存泄漏-ValueAnimator

检查代码的时候发现了一个内存泄漏的问题,导致Activity内存一直无法释放,后来发现是Activity内部的全局变量mValueAnimator无法释放而导致的。
代码分析
我们先看到代码,为了实现一个动画效果,我们在Activity内放置了一个ValueAnimator的全局变量,并且调用开启动画的方法。假设有如下无限循环动画:
Android内存优化- 方式十二: Animator的使用与释放(Android 内存泄漏)
然而,在没有做任何操作之后退出了Activity页面,这时候出现了内存泄漏,通过分析Java Head内存,我们发现是mValueAnimator对象没有得到释放导致。
于是我们在Activity#onDestory()方法中添加了代码
Android内存优化- 方式十二: Animator的使用与释放(Android 内存泄漏)
结果和预期一样,内存泄漏不再出现了。
那么为什么不对ValueAnimator动画做取消动作,就会出现内存泄漏呢?
我们看到ValueAnimator源码就能得到答案。
我们直接看到ValueAnimator#cancel()方法
Android内存优化- 方式十二: Animator的使用与释放(Android 内存泄漏)
基本看起来,都没有什么释放引用的操作,那么直接看到最后一行,继续查看endAnimation()方法。
Android内存优化- 方式十二: Animator的使用与释放(Android 内存泄漏)
好了,我们已经找到了,AnimationHandler实现了单例模式,这里AnimationHandler移除了ValueAnimator的动画监听回调。如果我们不调用ValueAnimator#cancel方法,使得AnimationHandler这个单例对象释放ValueAnimator的引用,ValueAnimator对象的内存就会得不到释放,也就造成了内存泄漏。
因此,很简单,我们在使用动画类的时候,要注意在生命周期结束的时候,取消或者停止动画,以防出现内存泄漏问题。