属性动画引起的内存泄露

在使用ValueAnimator或者ObjectAnimator时(ObjectAnimator继承ValueAnimator),如果没有及时做cancel取消动画,就可能造成内存泄露。因为在cancel方法里,最后调用了endAnimation(); ,在endAnimation里,有个AnimationHandler的单例,会持有属性动画对象的引用,属性对象持有view的引用,view持有activity引用,所以导致的内存泄露。

分析:
动画开启

objectAnimator.start()


objectAnimator继承ValueAnimator,接下来查看ValueAnimator的start方法。

@Override
    public void start() {
        AnimationHandler.getInstance().autoCancelBasedOn(this);
        if (DBG) {
            Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
            for (int i = 0; i < mValues.length; ++i) {
                PropertyValuesHolder pvh = mValues[i];
                Log.d(LOG_TAG, "   Values[" + i + "]: " +
                    pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
                    pvh.mKeyframes.getValue(1));
            }
        }
        super.start();
    }


ValueAnimator的start方法

@Override
    public void start() {
        start(false);
    }
private void start(boolean playBackwards) {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        ********省略部分代码***********
        addAnimationCallback(0);
        ********省略部分代码***********
    }

private void addAnimationCallback(long delay) {
        if (!mSelfPulse) {
            return;
        }
        getAnimationHandler().addAnimationFrameCallback(this, delay);
    }


可以看到这里有一个AnimationHandler的单例

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

public static AnimationHandler getInstance() {
        if (sAnimatorHandler.get() == null) {
            sAnimatorHandler.set(new AnimationHandler());
        }
        return sAnimatorHandler.get();
    }


ValueAnimator实现了AnimationFrameCallback接口,AnimationHandler持有了动画对象的引用

public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
        if (mAnimationCallbacks.size() == 0) {
            getProvider().postFrameCallback(mFrameCallback);
        }
        if (!mAnimationCallbacks.contains(callback)) {
            mAnimationCallbacks.add(callback);
        }

        if (delay > 0) {
            mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
        }
    }


接下来我们看看取消动画的代码

@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;
        }
        ********省略部分代码***********
        endAnimation();

    }

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

        mAnimationEndRequested = true;
       ********省略部分代码***********
    }


可以看到在调用cancel的时候,将AnimationHandler持有的引用移除

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


public void removeCallback(AnimationFrameCallback callback) {
        mCommitCallbacks.remove(callback);
        mDelayedCallbackStartTime.remove(callback);
        int id = mAnimationCallbacks.indexOf(callback);
        if (id >= 0) {
            mAnimationCallbacks.set(id, null);
            mListDirty = true;
        }
    }


总结:ObjectAnimator继承了ValueAnimator,ValueAnimator实现了AnimationFrameCallback接口,在开启动画的时候,AnimationHandler持有了ValueAnimator或ObjectAnimator的引用,因此在activity销毁的时候要保证属性动画执行完毕或者手动调用cancel方法。
————————————————
版权声明:本文为CSDN博主「缘尽&amp;渺如梦」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36356379/article/details/97125062

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值