循环播放AnimationSet导致StackOverflowError

4

我正在开发一个安卓应用程序,其中有一个无限重复的动画,导致了StackOverflowError。当在同一对象上启动另一个动画时,它会出现这种情况。

private fun pulse() {
    val randomGenerator = Random()

    val durationx = randomGenerator.nextInt(4000) + 1500

    val inflateX = ObjectAnimator.ofFloat(mContentView, "scaleX", 1.3f).apply {
        duration = durationx.toLong()
    }
    val inflateY = ObjectAnimator.ofFloat(mContentView, "scaleY", 1.3f).apply {
        duration = durationx.toLong()
    }
    val deflateX = ObjectAnimator.ofFloat(mContentView, "scaleX", 1.0f).apply {
        duration = durationx.toLong()
    }
    val deflateY = ObjectAnimator.ofFloat(mContentView, "scaleY", 1.0f).apply {
        duration = durationx.toLong()
    }
    val rotate = ObjectAnimator.ofFloat(mContentView, "rotation", 1.0f).apply {
        duration = durationx.toLong()
    }
    val soulToButton = AnimatorSet().apply {
        play(inflateX).with(inflateY)
        play(rotate).with(inflateX)
        play(deflateX).after(inflateX)
        play(deflateY).after(inflateY)
        start()
    }

    soulToButton.addListener(object: AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            super.onAnimationEnd(animation)
            soulToButton.start() // stacktrace points to this line as cause for the error.
        }
    })
    soulToButton.start()

    AnimatorSet().apply {
        play(soulToButton)
        start()
    }
}

我尝试将函数更改为 fun pulse(stop: boolean),在开始脉冲时调用 pulse(false),在其他动画开始之前调用pulse(true),并在多个位置添加if (stop) {soulToButton.cancel()}。我还尝试像这样包装导致错误的代码行:while(stop == false){soultoButton.start()}。但所有这些都没有帮助。

刚刚尝试在一个空项目设置中,仅使用这段代码进行复现 - 运行时没有任何异常。有没有什么线索可以复现它? - azizbekian
  1. 你调用pulse函数的次数是多少?也许具体的情况可以帮助解决问题。
  2. 最后三行代码应该被删除,因为它们会创建额外的AnimatorSet。
  3. 如答案所述,你应该将repeatCount设置为无限,而不是在动画结束时再次调用soulToButton AnimatorSet。
- Sowmia Sundararajan
3个回答

3

虽然使用了 Kotlin 语言,但仍然运行在 Java 虚拟机(JVM)上,因此 JVM 的限制仍然有意义。因此,如果你不断调用一个函数,会导致 JVM 栈溢出错误,无法无限制地执行。

有一些特殊的函数可以帮助你无限制地运行动画。例如

objectAnimator.setRepeatCount(ObjectAnimator.INFINITE);

或者在你的情况下

ObjectAnimator.ofFloat(mContentView, "scaleX", 1.3f).apply {
        duration = durationx.toLong()
        repeatCount = ObjectAnimator.INFINITE
    }

当您以相同的方式修改所有动画并将它们链接在AnimatorSet中时,其start函数将无限次播放此动画,而不会出现StackOverflowError。

希望这能帮助您。


3

试用这个版本:它简短明了,基本上做同样的事情。

    val randomGenerator = Random()

    val durationx = randomGenerator.nextInt(4000) + 1500

    val animator = animator@{ property : String, value : Float ->
        return@animator ObjectAnimator.ofFloat(mContextView, property, value).apply {
            duration = durationx.toLong()
            repeatMode = REVERSE
            repeatCount = INFINITE
        }
    }

    AnimatorSet().apply {
        playTogether(animator("scaleX", 1.3f),animator("scaleY", 1.3f),animator("rotation", 45.0f))
        start()
    }

1

在这里,您正在尝试在动画完成后再次启动动画,

soulToButton.addListener(object: AnimatorListenerAdapter() {
        override fun onAnimationEnd(animation: Animator) {
            super.onAnimationEnd(animation)
            soulToButton.start() // This will start the animation again without an end to the animation hence the StackOverflow error.
        }
    })

为了使动画无限运行,请使用以下代码段:
val inflateX = ObjectAnimator.ofFloat(mContentView, "scaleX", 1.3f).apply {
        duration = durationx.toLong()
        repeatCount = ObjectAnimator.INFINITE
        }

val soulToButton = AnimatorSet().apply {
        play(inflateX).with(inflateY)
        play(rotate).with(inflateX)
        play(deflateX).after(inflateX)
        play(deflateY).after(inflateY)

    }

soulToButton.start()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接