今天终于StackOverflow了

本文通过一个具体的案例,详细解析了在特定业务场景下触发StackOverflow的原因。主要涉及Lottie动画的管理与取消播放的过程,指出在动画取消播放时的不当处理方式,并给出了相应的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天终于StackOverflow了

【2020年11月11号 23:51:00】bug还是要有的,不然多无聊啊…


0. 背景

在一个特定的业务场景下,播放一个lottie动画,但在播放动画中,用户可以关掉这个业务场景,此时就会必现StackOverflow。

1. bug描述

(1) 涉及到的代码

// 有一个管理动画的类
class XxxAnimationViewController {
  // 定义一个Lottie动画的View
  LottieView mXxxAnimationView;
  
  XxxAnimationViewController(...) {
    mXxxAnimationView.addAnimatorListener(new Animator.AnimatorListener() {
	  @Override
	  public void onAnimationEnd() {
		stopLottieAnimation();
	  }

	  @Override
	  public void onAnimationCancel() {
		stopLottieAnimation();
	  }
	});
  }

  public void stopLottieAnimation() {
	if (mXxxAnimationView == null || !mXxxAnimationView.isAnimating()) {
	  // 如果动画没有在播放,就直接return
	  return;
	}
	mXxxAnimationView.cancelAnimation();
	mXxxAnimationView.setImageDrawable(null);
  }
}

// 还有一个处理具体业务的类
class XxxPart {
  
  
  // new Controller对象
  XxxAnimationViewController controller = new XxxAnimationViewController();
  
  // 当用户关掉了这个业务场景
  void onUserCloseScene() {
	controller.stopLottieAnimation();
  }
}

然后看堆栈,就会发现,一直在调用cancelAnimation()方法,一直调,大约消耗了8M内存后,蹦了…

2. 分析

明明在调用cancelAnimation方法之前判断了lottie动画是否已经停止播放,为什么还会一直反复的调用cancelAnimation方法呢?

  • 看LottieAnimationView#isAnimating()源码,发现,这个方法其实是return了一个标识符的东西(running变量),只有当标识符被赋值为false的时候,才能说lottie动画停止播放了。
  • 但这个变量(running)什么时候被赋值的呢?【先接着往下看,看看cancelAnimation()这个方法】
  • 当调用LottieAnimationView#cancelAnimation()方法后,会接着走LottieDrawable#cancelAnimation() ,LottieValueAnimator#cancel()。
  • 在最后这个cancel()方法中,一共调用了两个方法notifyCancel()和removeFrameCallback():
    (1)notifyCancel的作用是 调了Animator的onAnimationCancel()回调方法。【注意: 此时running这个标识符一直没有被置位false,也就是可以’‘认为’'lottie动画一直在播放。】
    (2)removeFrameCallback的作用才是将running置为false,此时再调用isAnimating()方法,返回的才是false,即动画停止了。
    (3)我又在onAnimationCancel方法中,调用了stopLottieAnimation()方法
    综合上述三点,赋值时机+错误调用stop方法,最终导致了StackOverflow

3. 避免再掉坑

  • 其实在onAnimationCancel和onAnimationEnd这两个方法中,真正要做的并不是"停掉动画",而是reset动画,如LottieXxxView的可见性置为GONE,LottieXxxView的ImageDrawable置为null。
  • 既然有addAnimatorListener操作,就要考虑在合适的位置上removeAllAnimatorListeners。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值