I am delevolping an android app in which I have an infinitely repeating animation that is causing a StackOverflowError. It does this, when another animation on the same object is started.
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()
}
}
I tried changing the function to fun pulse(stop: boolean), calling pulse(false) for starting the pulse and pulse(true) before the other animation starts, and adding if (stop) {soulToButton.cancel()} in several places. I also tried wrapping the line causing the error like this: while(stop == false){soultoButton.start()}
All of this didn´t help.
It is Kotlin but it is still Java and all the JVM limitations are relevant here. Thus you cannot call one function indefinitely without causing StackOverflowError since the JVM stack is limited.
There are special functions that will help you to run the animation indefinitely. For example
objectAnimator.setRepeatCount(ObjectAnimator.INFINITE);
Or in your case
ObjectAnimator.ofFloat(mContentView, "scaleX", 1.3f).apply {
duration = durationx.toLong()
repeatCount = ObjectAnimator.INFINITE
}
After you modify all your animations the same way and chain them in AnimatorSet its start function will play this animation indefinite time without StackOverflowError.
Hope it helps.
Try out this version: its short and concise and basically doing the same thing.
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()
}
You are trying to start animation again after it has completed in here ,
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.
}
})
In order to run an animation for infinite time use the following piece of code,
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()