Search code examples
androidloopskotlinandroid-animationstack-overflow

Looping an AnimationSet causes StackOverflowError


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.


Solution

  • 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()
        }