Search code examples
androidkotlinkotlin-extensionandroid-ktx

Android KTX: how to override Kotlin added property extension


I am trying to override View.setRotation() method in Kotlin.

Since AndroidKTX already provided property extension "rotation", caller's can simply call

viewObject.rotation = 90.0f

to rotate the view.

However, I want to add some additional operation when user change the rotation, like

override fun setRotation(newRotation: Float) {
    if (rotation == newRotation)
        return
    rotation = newRotation
    doSomethingElse()
}

This will crash because of StackOverflow error.

So, I have to add some additional code to achieve the goal:

    private var _rotation: Float = 0.0f
    override fun setRotation(newRotation: Float) {
        if (_rotation == newRotation) {
            return
        }
        _rotation = newRotation
        updateRotationInternally()
    }

    private fun updateRotationInternally() {
        super.setRotation(_rotation)
        doSomethingElse()
    }

This works, but I wonder if there is some other more elegant way of doing this, like "override the property extension setter"?


Solution

  • I disagree with one aspect of your implementation: your return shortcut. You are assuming that calling setRotation() with the existing rotation value has no effect. It would not surprise me if that is true in the official Google version of View, but for all we know, that is not a safe assumption on some Oppo device running their modified version of Android 8.0. Try not to assume the behavior of stuff that you didn't write. If you want to skip doSomethingElse() when the old and new rotations are equal, that's fine.

    I am guessing that your setRotation() functions are in some subclass of View. If so, and taking my above complaint into account, here's the simplest that I could come up with:

    class Bar : View() {
      override fun setRotation(f: Float) {
        val needSomething = getRotation() != f
    
        super.setRotation(f)
    
        if (needSomething) doSomethingElse()
      }
    
      fun doSomethingElse() {
        println("got here!")
      }
    }
    

    My overall test code was done in a Kotlin scratchpad (outside of Android), so I tested with a fake View implementation and fake rotation extension property:

    open class View {
      private var r: Float = 0.0f
    
      open fun setRotation(f: Float) {
        r = f
      }
    
      fun getRotation() = r
    }
    
    var View.rotation: Float
      get() = getRotation()
      set(value) = setRotation(value)
    
    class Bar : View() {
      override fun setRotation(f: Float) {
        val needSomething = getRotation() != f
    
        super.setRotation(f)
    
        if (needSomething) doSomethingElse()
      }
    
      fun doSomethingElse() {
        println("got here!")
      }
    }
    
    fun main() {
      val bar = Bar()
    
      bar.rotation = 15.0f
      bar.rotation = 15.0f
    }
    

    If you run this in that scratchpad, you will see got here printed on the console once, showing that while we successfully updated the extension property twice, we skipped getSomethingElse() on the second call, as the old and new rotation were the same.