How can I refactor my kotlin code and make it more clear

Hayk Mkrtchyan :

I'm a beginner in kotlin, but I know java. So I've created a program, where I have one textview. It will change it's test every 1sec with fade animation. So my program works fine, but as I'm beginner in kotlin, can you help me or give a feedback related to my code. Also if I wrote something wrong, you can edit it without any problem :)

class MainActivity : AppCompatActivity() {

private lateinit var fadeInAnimation: Animation
private lateinit var fadeOutAnimation: Animation
private lateinit var handler: Handler
private lateinit var myRunnable: Runnable
private val textArray: Array<String> = arrayOf("This", "is", "fading", "text")
private var textPosition: Int = 0


companion object {
    private const val ANIM_DURATION: Long = 1000L
}


override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)


    fadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_in)
    fadeOutAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_out)
    handler = Handler()

    initRunnable()
}


override fun onResume() {
    super.onResume()
    startAnimation()
}


override fun onPause() {
    super.onPause()
    stopAnimation()
}


private fun initRunnable() {
    myRunnable = Runnable {
        text_view.animation = fadeOutAnimation
        fadeOutAnimation.start()
        fadeOutAnimation.setAnimationListener(object : AnimationListener() {
            override fun onAnimationEnd(animation: Animation?) {
                textPosition = when (textPosition) {
                    textArray.size - 1 -> 0
                    else -> ++textPosition
                }

                startAnimation()
            }
        })
    }
}


private fun startAnimation() {
    text_view.text = textArray[textPosition]
    text_view.animation = fadeInAnimation
    fadeInAnimation.start()

    handler.postDelayed(myRunnable, ANIM_DURATION)
}


private fun stopAnimation() {
    handler.removeCallbacksAndMessages(null)
    fadeInAnimation.cancel()
    fadeOutAnimation.cancel()
}

}

Please leave feedback related to my code, how can I make it more clear, or maybe something I've done not right, or maybe something is not a practice? Thank you.

Tenfour04 :

I would create one single animation in XML that does the fade in, delay, and fade out. Then you wouldn't need to use the handler to post the fade-out or juggle two animations. But since we're just looking at the Kotlin code:

  1. There's no reason for the Runnable to even have a property if you're never using it again. Also, there's a postDelayed extension function that swaps the argument order so you can use a trailing lambda. (You could alternatively store the Runnable in a val so it's only instantiated once like in the comment from @Mostafa, but in my opinion it's trivially small and the code is clearer if you keep it at the location it's used.)
  2. You can simplify decrementing textPosition with the remainder operator (also would apply to Java).
  3. If your companion object has nothing but private constants, it's better to move it outside the class because companion objects get compiled as a new class and have an instance.
  4. You only need to set the animation listener once.

private const val ANIM_DURATION: Long = 1000L

class MainActivity : AppCompatActivity() {

    private lateinit var fadeInAnimation: Animation
    private lateinit var fadeOutAnimation: Animation
    private lateinit var handler: Handler
    private val textArray: Array<String> = arrayOf("This", "is", "fading", "text")
    private var textPosition: Int = 0    

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        fadeInAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_in)
        fadeOutAnimation = AnimationUtils.loadAnimation(this, R.anim.fade_out).apply {
            setAnimationListener(object : AnimationListener() {
                override fun onAnimationEnd(animation: Animation?) {
                    textPosition = (textPosition - 1 + textArray.size) % textArray.size
                    startAnimation()
                }
            })
        }
        handler = Handler()
    }

    override fun onResume() {
        super.onResume()
        startAnimation()
    }

    override fun onPause() {
        super.onPause()
        stopAnimation()
    }

    private fun startAnimation() {
        text_view.text = textArray[textPosition]
        text_view.animation = fadeInAnimation
        fadeInAnimation.start()
        handler.postDelayed(ANIM_DURATION) {
            text_view.animation = fadeOutAnimation
            fadeOutAnimation.start()
        }
    }

    private fun stopAnimation() {
        handler.removeCallbacksAndMessages(null)
        fadeInAnimation.cancel()
        fadeOutAnimation.cancel()
    }
}

Also, if you define your animations using ObjectAnimator instead of the older Animations API, you can use doOnEnd instead of the more clunky anonymous AnimationListener.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=342125&siteId=1