The interfaces in Kotlin will allow you to reuse more code than what you can get with Java.
The reason is very simple: you can add code to your interfaces. If you’ve tried Java 8, it’s something pretty similar.
The good thing about being able to include code in an interface is that you can use composition in a much more powerful way. We’ll see in a minute.
Would you like to start today to take the next step? I recommend that you sign up to my free training here.
Interfaces in Java 6
The problem with Java interfaces is that we can only describe behavior, but not implement it.
This is enough in many cases. But there are situations that we can’t solve because it forces us to delegate the implementation of this interface in individual objects if we want to achieve a good composition.
All this makes something as simple composing the code of a class using reusable pieces rather complicated.
Interfaces in Kotlin
Kotlin brings us some very good news: interfaces can have code.
This means that we can implement a kind of multiple inheritance (somewhat limited, in any case). We can make a class implement several interfaces, and inherit the behavior from each one.
To write an interface that includes some methods implemented, you don’t need anything special:
interface Interface1 { fun function1() { Log.d("Interface1", "function1 called") } }
We could have another interface 2 with another function:
interface Interface2 { fun function2() { Log.d("Interface2", "function2 called") } }
And a class that implements them could use both without problem:
class MyClass : Interface1, Interface2 { fun myFunction() { function1() function2() } }
Great! This gives us much more versatility when organizing our code.
Interfaces can’t keep state
It’s an important limitation to keep in mind. We can have code but not state.
This means that we can’t create a property and store the state in it. If we define a property in an interface, the class that implements it needs to overwrite it.
Let’s see an example. Imagine that the interface needs a context:
interface Toaster { val context: Context fun toast(message: String) { Toast.makeText(context, message, Toast.LENGTH_SHORT).show() } }
The code is simple. It’s an interface that implements a method that displays a Toast
. It requires a context to do that.
If we have an activity that wants to use this interface, it needs to overwrite the context:
class MyActivity : AppCompatActivity(), Toaster { override val context = this override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) toast("onCreate") } }
As simple as that. We assign the Activity
itself as a context, and the interface will use it.
Now you can use the Toaster
functions in the Activity
without any problems.
Interface delegation
Another very interesting feature in Kotlin is the interface delegation. It is a very powerful tool to achieve a cleaner composition.
Imagine that you have a class C, composed of two objects of type A and B:
interface A { fun functionA(){} } interface B { fun functionB(){} } class C(val a: A, val b: B) { fun functionC(){ a.functionA() b.functionB() } }
Class C uses functions A and B within its own code.
If an object is composed by other components, it’d be very good that it could use their functions directly.
There is another way to write this code and get the same result, using the interface delegation:
class C(a: A, b: B): A by a, B by b { fun functionC(){ functionA() functionB() } }
You can see that class C is implementing A and B, but it’s actually delegating the implementation to the objects it receives as a parameter.
By using interface delegation, the class can use functions from implemented classes directly and still delegate the implementation to other objects.
Conclusion
We’ve seen the differences between Java interfaces and those of Kotlin. Now try to find out what situations can simplify your life, because these new ideas open a world of possibilities.
Your code will be more reusable than before and much more readable.
Still not convinced about Kotlin for Android? Start using it as soon as possible! Thanks to the the previous articles you can learn more about Kotlin, or I recommend that you sign up to my free training here.
If kotlin allows method implementation in interfaces and we can implement multiple interfaces in a class, doesn’t this create a diamond problem? for what we got interfaces in the first place.
That’s solved like this: In Kotlin, implementation inheritance is regulated by the following rule: if a class inherits many implementations of the same member from its immediate superclasses, it must override this member and provide its own implementation
https://kotlinlang.org/docs/reference/classes.html#overriding-rules
I cannot figure out a syntax and need help. This is a simple interface with one function (come on lambda!)
interface Callback {
fun call(requestCode: Int, resultCode: Int, data: Intent?)
}
But I have to call it like this:
startActivityForResult(intent, 10, object: Callback {
override fun call(requestCode: Int, resultCode: Int, data: Intent?) { doSomething() }
})
whereas I want to do something like this (what we do with setOnClickListener() or DialogInterface.OnClickListener):
startActivityForResult(intent, 10, Callback { _, _, _ -> doSomething() })
But it gives syntax error “Interface Callback does not have constructor.”
The simplification of interfaces is only done if the code is written in Java. For Kotlin, you have the ability to use functions as a type, so you don’t need to write the interface. The declaration of the function would be:
fun startActivityForResult(intent: Intent, resultCode: Int, callback: (Int, Int, Intent?) -> Unit){
...
}
Okay now the lambda syntax is working, but there is still one thing
How will I call this callback? I mean look at the following code please
private var callback: Callback? = null
fun startActivityForResult(intent: Intent, requestCode: Int, callback: (Int, Int, Intent?) -> Unit) {
super.startActivityForResult(intent, requestCode)
this.callback = callback // THIS LINE HAS THE ERROR
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
callback?.call(requestCode, resultCode, data)
callback = null
}
So the problem is how to save (Int, Int, Intent?) -> Unit in a variable and then call it later?
By using that type into the variable:
private var callback: ((Int, Int, Intent?) -> Unit)? = null
You could even a typealias to make it simpler to read if this becomes messy.
typealias Callback = (Int, Int, Intent?) -> Unit
So doesn’t this make them abstract classes?
No, because you can only extend from one abstract class, and the abstract class can hold state. On the other hand, you can implement several interfaces, but interfaces can’t hold state.