3
votes

La boucle d'un AnimationSet provoque une erreur StackOverflowError

Je suis en train de supprimer une application Android dans laquelle j'ai une animation qui se répète à l'infini qui provoque une StackOverflowError. Il le fait lorsqu'une autre animation sur le même objet est lancée.

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

J'ai essayé de changer la fonction en fun pulse (stop: boolean) , en appelant pulse (false) pour démarrer l'impulsion et pulse (true) avant le début de l'autre animation, et en ajoutant if (stop) {soulToButton.cancel ()} à plusieurs endroits. J'ai aussi essayé d'encapsuler la ligne provoquant l'erreur comme ceci: while (stop == false) {soultoButton.start ()}

Tout cela n'a pas aidé. p>


2 commentaires

Je viens d'essayer de reproduire sur une configuration de projet vide avec seulement ce morceau de code - fonctionne sans aucune exception. Un indice sur la manière de le reproduire?


1. combien d'endroits appelez-vous la fonction d'impulsion? peut être le scénario exact peut aider. 2. Les trois dernières lignes de code doivent être supprimées car il crée un jeu d'animateurs supplémentaire. 3. Comme décrit dans les réponses, vous devez utiliser repeatcount comme infini au lieu d'appeler à nouveau soulToButton animatorset à la fin de l'animation.


3 Réponses :


3
votes

C'est Kotlin mais c'est toujours Java et toutes les limitations de la JVM sont pertinentes ici. Ainsi, vous ne pouvez pas appeler une fonction indéfiniment sans provoquer StackOverflowError car la pile JVM est limitée.

Il existe des fonctions spéciales qui vous aideront à exécuter l'animation indéfiniment. Par exemple

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

Ou dans votre cas

objectAnimator.setRepeatCount(ObjectAnimator.INFINITE);

Après avoir modifié toutes vos animations de la même manière et les enchaîner dans AnimatorSet sa fonction start jouera cette animation indéfiniment sans StackOverflowError.

J'espère que cela aide.


0 commentaires

1
votes

Vous essayez de redémarrer l'animation une fois qu'elle est terminée ici,

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

Pour exécuter une animation pendant une durée infinie, utilisez le morceau de code suivant,

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.
        }
    })


0 commentaires

3
votes

Essayez cette version: elle est courte et concise et fait essentiellement la même chose.

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


0 commentaires