@@ -3,12 +3,13 @@ package com.algolia.instantsearch.voice.ui
33import android.animation.AnimatorSet
44import android.content.Context
55import android.graphics.Canvas
6+ import android.os.Looper
67import android.util.AttributeSet
78import android.view.View
8- import kotlinx.coroutines.experimental.Job
9+ import kotlinx.coroutines.experimental.*
10+ import kotlinx.coroutines.experimental.android.Main
911import kotlinx.coroutines.experimental.android.UI
10- import kotlinx.coroutines.experimental.delay
11- import kotlinx.coroutines.experimental.launch
12+ import kotlinx.coroutines.experimental.android.awaitFrame
1213
1314/* * A View displaying a ripple effect. */
1415class RippleView : View {
@@ -39,7 +40,8 @@ class RippleView : View {
3940 private var radius: Float = 0f
4041 private var size: Int = 0
4142
42- private lateinit var jobAnimation: Job
43+ private var jobAnimation: Job ? = null
44+ private var jobFps : Job ? = null
4345
4446 private var state = State .None
4547 set(value) {
@@ -51,14 +53,33 @@ class RippleView : View {
5153 jobAnimation = animation()
5254 }
5355 State .Stopped -> try {
54- jobAnimation.cancel()
56+ jobAnimation?.cancel()
57+ jobAnimation = null
5558 } catch (e: UninitializedPropertyAccessException ) {
5659 // cancel() was called before start()
5760 }
5861 State .None -> Unit
5962 }
6063 }
6164
65+ override fun onAttachedToWindow () {
66+ super .onAttachedToWindow()
67+ jobFps = GlobalScope .launch(Dispatchers .Main ) {
68+ while (isActive) {
69+ awaitFrame()
70+ invalidate()
71+ }
72+ }
73+ }
74+
75+ override fun onDetachedFromWindow () {
76+ super .onDetachedFromWindow()
77+ jobFps?.cancel()
78+ jobFps = null
79+ jobAnimation?.cancel()
80+ jobAnimation = null
81+ }
82+
6283 private fun init (attrs : AttributeSet ) {
6384 context.obtainStyledAttributes(attrs, R .styleable.RippleView , 0 , 0 ).also {
6485 val drawable = it.getDrawable(R .styleable.RippleView_drawable )
@@ -70,18 +91,10 @@ class RippleView : View {
7091
7192 circles = (0 until circleCount).map { DrawableSprite (drawable, size, Opacity .p0) }
7293 }.recycle()
73- launch(UI ) {
74- // This coroutine refreshes the view at 60 fps
75- while (isActive) {
76- UI .awaitFrame()
77- invalidate()
78- }
79- }
8094 }
8195
8296 /* * This coroutine generates an animation at each [interval][circleCount]. */
83- private fun animation (): Job = launch(UI ) {
84-
97+ private fun animation (): Job = GlobalScope .launch(Dispatchers .Main ) {
8598 var index = 0
8699 while (isActive) {
87100 animations[index] = circles[index].circleAnimation().also { it.start() }
0 commit comments