Android(安卓)内存泄漏 - Animator的使用与释放
16lz
2021-01-25
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的内存始终无法被回收。
更多相关文章
- Android(安卓)ViewFlipper实现页面的滑动切换
- Handler sendMessage 与 obtainMessage (sendToTarget)比较
- Android(安卓)Camera 四 Camera HAL 分析
- 安卓指定横竖屏失效问题修复
- android camera HAL v3.0详细介绍(二)
- 如何解决向eclipse导入android project时遇到错误“Invalid proj
- Android培训班(30)
- Android(安卓)shap Animation
- Android(安卓)Volley