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函数的源码:

@Override    public void cancel() {        if (Looper.myLooper() == null) {            throw new AndroidRuntimeException("Animators may only be run on Looper threads");        }        // If end has already been requested, through a previous end() or cancel() call, no-op        // until animation starts again.        if (mAnimationEndRequested) {            return;        }        // Only cancel if the animation is actually running or has been started and is about        // to run        // Only notify listeners if the animator has actually started        if ((mStarted || mRunning) && mListeners != null) {            if (!mRunning) {                // If it's not yet running, then start listeners weren't called. Call them now.                notifyStartListeners();            }            ArrayList tmpListeners =                    (ArrayList) mListeners.clone();            for (AnimatorListener listener : tmpListeners) {                listener.onAnimationCancel(this);            }        }        endAnimation();    }

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

private void endAnimation() {        if (mAnimationEndRequested) {            return;        }        removeAnimationCallback();        ......}

继续看到removeAnimationCallback()函数:

private void removeAnimationCallback() {        if (!mSelfPulse) {            return;        }        getAnimationHandler().removeCallback(this);    }

其中getAnimationHandler()函数:

public AnimationHandler getAnimationHandler() {        return AnimationHandler.getInstance();    }

可以看出,其中可以猜想到getAnimationHandler()获取的应该是单例:

public final static ThreadLocal sAnimatorHandler = new ThreadLocal<>();    private boolean mListDirty = false;    public static AnimationHandler getInstance() {        if (sAnimatorHandler.get() == null) {            sAnimatorHandler.set(new AnimationHandler());        }        return sAnimatorHandler.get();    }

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

更多相关文章

  1. Android(安卓)ViewFlipper实现页面的滑动切换
  2. Handler sendMessage 与 obtainMessage (sendToTarget)比较
  3. Android(安卓)Camera 四 Camera HAL 分析
  4. 安卓指定横竖屏失效问题修复
  5. android camera HAL v3.0详细介绍(二)
  6. 如何解决向eclipse导入android project时遇到错误“Invalid proj
  7. Android培训班(30)
  8. Android(安卓)shap Animation
  9. Android(安卓)Volley

随机推荐

  1. Android(安卓)音乐裁剪器
  2. Android(安卓)Reference官方描述
  3. Android(安卓)Studio - 快捷键详解-MAC版
  4. android中获取当前Activity的实例和名字
  5. android 摄像头的调用
  6. 最近总结的android疑惑(二)
  7. Android(安卓)EditText自定义样式的方法
  8. Android之Animation全介绍
  9. Android浏览器插件开发-Log
  10. 为TextView设置边框