Object Expressions

Frequently, we need to pass an instance of an object to some function, where we need a tailored instance of the desired class, with custom functionality.

In Java, this is where the “anonymous inner class” comes into play:

void clickyClickyClicky(View view) {
  view.setOnClickListener(new OnClickListener() {
    @Override
    public void onClick(View v) {
      // TODO something useful
    }
  });
}

This sort of code will be familiar to long-time Android developers. To find out when this UI element (a View) gets clicked, we can call setOnClickListener(), providing an implementation of a OnClickListener interface. Rather than create a standalone class, though, we use anonymous inner class syntax to create a class and a single instance of that class.

Kotlin’s equivalent of that sort of syntax is the “object expression”.

Basic Declaration

The Kotlin equivalent of the View and OnClickListener from above might look like this:

interface OnClickListener {
  fun onClick(v: View)
}

class View {
  fun setOnClickListener(listener: OnClickListener) {
    // TODO something with this
  }
}

(technically, in Android, OnClickListener is a nested interface inside of View — we will explore that pattern in an upcoming chapter)

We have the View class and an OnClickListener interface, along with a setOnClickListener() function.

When we want to call setOnClickListener(), we could create a standalone class that implements the OnClickListener interface. Or, we could use an object expression instead:

fun clickyClickyClicky(view: View) {
  view.setOnClickListener(object : OnClickListener {
    override fun onClick(v: View) {
      // TODO something useful
    }
  })  
}

The object keyword indicates that we are creating a single object, and the : OnClickListener indicates that this object will implement the OnClickListener interface. From there, it is no different than any other interface implementation: we override the onClick() function and do whatever it is that we want to do.

Constructors and Parameters

Object expressions can extend other classes and implement interfaces. The notation is pretty much the same as when you have a class extend other classes and implement interfaces. The biggest difference is that you use the object keyword in place of the class name.

In the above example, OnClickListener is an interface. As a result, our object expression could just have the interface name after the colon (: OnClickListener) to implement it, because interfaces have no constructors. Classes do, so if OnClickListener were an abstract class, you would need to invoke a constructor in your object expression:

abstract class OnClickListener {
  abstract fun onClick(v: View)
}

class View {
  fun setOnClickListener(listener: OnClickListener) {
    // TODO something with this
  }
}

fun clickyClickyClicky(view: View) {
  view.setOnClickListener(object : OnClickListener() {
    override fun onClick(v: View) {
      // TODO something useful
    }
  })  
}

Access Rules

Your object expression has access to anything that is available to other Kotlin code in the same scope. So, for example, if there is a local variable in a function where the object expression is declared, the local variable is accessible by the object expression’s own code:

fun clickyClickyClicky(view: View) {
  var clicks = 0

  view.setOnClickListener(object : OnClickListener() {
    override fun onClick(v: View) {
      clicks++
      println(clicks)
    }
  })  
}

In Java, this requires the final keyword to work, and you would not be allowed to modify the value the way we are doing here. Kotlin is more flexible: you do not need any keywords and you have normal access to the variable.

The SAM Scenario

On occasion, you will find Kotlin code that seems to be akin to an object expression but just has a lambda for its implementation:

val listener = OnClickListener { v: View -> ... }

(where ... is some useful Kotlin code)

This is the single-abstract-method pattern. We will examine it in greater detail later in the book, because as it turns out, this only works if the interface being used (OnClickListener) is defined in Java, not in Kotlin.


Prev Table of Contents Next

This book is licensed under the Creative Commons Attribution-ShareAlike 4.0 International license.