From 376c8b37b93ef0c8cbee61182ae456e8a360d3eb Mon Sep 17 00:00:00 2001 From: Joshua Soberg Date: Thu, 30 Jan 2025 05:28:06 -0500 Subject: [PATCH] Fix memory leaks reported by LeakCanary but ending infinite animations when Activity is paused (#2103) --- .../habitica/ui/activities/ArmoireActivity.kt | 13 +++++++++++ .../android/habitica/ui/views/SparkView.kt | 23 ++++++++++++------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt index 08427734a..4a52c8fdc 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/ArmoireActivity.kt @@ -397,4 +397,17 @@ class ArmoireActivity : BaseActivity() { dialog.setContentView(R.layout.armoire_drop_rate_dialog) dialog.show() } + + override fun onPause() { + super.onPause() + // Clear infinite animations on pause to make sure Context references aren't leaked. + stopInfiniteAnimations() + } + + private fun stopInfiniteAnimations() { + binding.leftSparkView.stopAnimating() + binding.rightSparkView.stopAnimating() + binding.iconView.animation?.cancel() + binding.iconView.animation = null + } } diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/SparkView.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/SparkView.kt index 3408201be..5034bcf3e 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/SparkView.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/SparkView.kt @@ -27,6 +27,7 @@ constructor( invalidate() } private var paint: Paint = Paint() + private var animator: ValueAnimator? = null var thickness = 3.dpToPx(context) var length = 6.dpToPx(context) @@ -59,15 +60,16 @@ constructor( } fun startAnimating() { - val anim = ObjectAnimator.ofFloat(thickness.toFloat(), maxSpacing.toFloat()) - anim.addUpdateListener { - spacing = it.animatedValue as Float + animator = ObjectAnimator.ofFloat(thickness.toFloat(), maxSpacing.toFloat()).apply { + addUpdateListener { + spacing = it.animatedValue as Float + } + interpolator = AccelerateDecelerateInterpolator() + repeatCount = Animation.INFINITE + repeatMode = ValueAnimator.REVERSE + duration = animationDuration + start() } - anim.interpolator = AccelerateDecelerateInterpolator() - anim.repeatCount = Animation.INFINITE - anim.repeatMode = ValueAnimator.REVERSE - anim.duration = animationDuration - anim.start() } override fun onMeasure( @@ -139,4 +141,9 @@ constructor( paint ) } + + fun stopAnimating() { + animator?.end() + animator = null + } }