I am converting some of my Java code to Kotlin and I do not quite understand how to instantiate interfaces that are defined in Kotlin code. As an example, I have an interface (defined in Java code):
public interface MyInterface {
void onLocationMeasured(Location location);
}
And then further in my Kotlin code I instantiate this interface:
val myObj = new MyInterface { Log.d("...", "...") }
and it works fine. However, when I convert MyInterface to Kotlin:
interface MyInterface {
fun onLocationMeasured(location: Location)
}
I get an error message: Interface MyListener does not have constructors
when I try to instantiate it - though it seems to me that nothing has changed except syntax. Do I misunderstand how interfaces work in Kotlin?
Your Java code relies on SAM conversion - an automatic conversion of a lambda into an interface with a single abstract method. SAM conversion is currently not supported for interfaces defined in Kotlin. Instead, you need to define an anonymous object implementing the interface:
val obj = object : MyInterface {
override fun onLocationMeasured(location: Location) { ... }
}
The best solution is to use a typealias in-place of your Java interface
typealias MyInterface = (Location) -> Unit
fun addLocationHandler(myInterface:MyInterface) {
}
Register it like this:
val myObject = { location -> ...}
addLocationHandler(myObject)
or even cleaner
addLocationHandler { location -> ...}
Invoke it like this:
myInterface.invoke(location)
The 3 current options seem to be:
- typealias (messy when called from java)
- kotlin interface (messy when called from kotlin; you need to create an object) This is a big step back IMO.
- java interface (less messy when called from kotlin; lambda needs interface name prepended so you don't need an object; also can't use lambda outside of function parenthesis convention)
When converting our libraries to Kotlin, we actually left all the interfaces in Java code, as it was cleaner to call Java from Kotlin than Kotlin from Kotlin.
if you have Java class like this :
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new RecyclerTouchListener.ClickListener()
{
//Your Code
}));
you shoud convert this code from Java to Kotlin like this :
override fun showJozList (list : List<ResponseGetJuzList.Parameter4>) {
adapter.addData(list)
jozlist_recycler.addOnItemTouchListener(RecyclerTouchListener(
activity ,
jozlist_recycler ,
object : RecyclerTouchListener.ClickListener
{
//Your Code
}))
convert Java Interface :
new RecyclerTouchListener.ClickListener()
to Kotlin Interface Style:
object : RecyclerTouchListener.ClickListener
Try to access to your interface like this :
object : MyInterface {
override fun onSomething() { ... }
}