Instantiating an Interface Listener in Kotlin

19,370

Solution 1

You can do watchers/listeners like this:

val textView: TextView = this.findViewById(R.id.amountEdit)
val watcher = object : TextWatcher {
    override fun afterTextChanged(p0: Editable?) {
        val inputAmount = textView.text.toString
        val amount = if (!inputAmount.isEmpty()) inputAmount.toDouble() else 0.0
        conversionViewModel?.convert(amount)
        }

    override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        println("before text changed called..")
    }

    override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        println("text changed..")
    }
}

and then:

textView.addTextChangedListener(watcher)

Notice the object in declaring the watcher. Can do the same with a listener.

Solution 2

Also we can use listener without some interface and with default value like:

val someButtonListener: (isChecked: Boolean) -> Unit = {_ -> }
val someButtonListener: (v: View) -> Unit = {_ -> }
Share:
19,370
Josh Ribeiro
Author by

Josh Ribeiro

Novice Android Programmer

Updated on July 23, 2022

Comments

  • Josh Ribeiro
    Josh Ribeiro almost 2 years

    I cannot, for the life of me, instantiate an interface outside of a fragment in Kotlin or Kotlin for Android. It was standard procedure in Java to say something like:

    MyInterface mInterfaceListener = new MyInterface(this);
    mInterfaceListener.invokeSomeGenericMethod();
    

    Note that mInterfaceListener is referring to an Interface, not an onCLickListener or anything like that

    How are interfaces instantiated in Kotlin? How do I make a "listener" and trigger an interface's functions?

    Below are some attempts in a very simple app I am doing for learning purposes. Notice the variable mPresenterListener which is an Interface

        class QuoteActivity : QuoteContract.ViewOps, AppCompatActivity() {
    
        private lateinit var vText: TextView
        private lateinit var vFab: FloatingActionButton
        private lateinit var mPresenterListener: QuoteContract.PresenterOperations
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            mPresenterListener = this.mPresenterListener
            vText=findViewById(R.id.main_quote)
            vFab=findViewById(R.id.main_fab)
            vFab.setOnClickListener{
                mPresenterListener.onQuoteRequested()
            }
        }
    
        override fun displayQuote(quote: String) {
            vText.text = quote
        }
    
    }
    

    And my presenter:

        class QuotePresenter(private val viewListener: QuoteContract.ViewOps): QuoteContract.PresenterOperations {
    
        private lateinit var modelListener: QuoteContract.ModelOperations
    
        init {
            modelListener = this.modelListener
        }
    
    
        override fun onQuoteRequested() {
            modelListener.generateQuote()
        }
    
        override fun onQuoteGenerated(quote: String) {
            viewListener.displayQuote(quote)
        }
    
    
    }
    

    The interface:

    interface QuoteContract {
    
    
    
    //Methods available to Presenter (Presenter -> View)
    interface ViewOps{
        fun displayQuote(quote: String)
    }
    
    
    //Ops offered from presenter to view (Presenter->View)
    
    interface PresenterOperations {
        //Presenter->View
        fun onQuoteRequested()
        //Presenter->Model
        fun onQuoteGenerated(quote: String)
    }
    
    //Ops offered from Model to Presenter (Model -> Presenter)
    interface ModelOperations {
        fun generateQuote()
    }
    

    }

  • Josh Ribeiro
    Josh Ribeiro over 6 years
    Ok, so just to wrap my head around your method: Textwatcher is an interface and you are assigning it to a singleton? How would this work in a typical MVP scenario? Thank you for your answer
  • Rob
    Rob over 6 years
    Why is it a singleton? it's an instance. This is one of the many great things about Kotlin: you can make instances out of interfaces, as objects.
  • Josh Ribeiro
    Josh Ribeiro over 6 years
    The mini-course I had taken defined the Singleton in Kotlin as an Object which can only have one instance of itself. I see Singleton sometimes in dependency injection, so I am not sure if there is some vocabulary overlap. Anyway, thank you for following up with my "answer". Yours is the answer, I just got lost with all the TextView shinnanigans and I wasn't sure if TextWatcher was an interface or some Android library class. Regardless, you helped me out and answered the question: assign it to an object. Much much easier than my solution. Thank you
  • Rob
    Rob over 6 years
    Sure, glad it helped @JoshRibeiro, good on you for wanting to learn the right way to do things. This question caught my eye because when I was learning the new Android Blueprints I had the exact question of how best to adapt the Java approach.