Estoy convirtiendo parte de mi código Java a Kotlin y no entiendo muy bien cómo instanciar interfaces que están definidas en el código Kotlin. Como ejemplo, tengo una interfaz (definida en código Java):
public interface MyInterface { void onLocationMeasured(Location location); }Y luego, más adelante en mi código Kotlin, instalo esta interfaz:
val myObj = new MyInterface { Log.d("...", "...") }y funciona bien Sin embargo, cuando convierto MyInterface a Kotlin:
interface MyInterface { fun onLocationMeasured(location: Location) } Recibo un mensaje de error: Interface MyListener does not have constructors cuando intento crear una instancia, aunque me parece que nada ha cambiado excepto la sintaxis. ¿Entiendo mal cómo funcionan las interfaces en Kotlin?
Su código Java se basa en la conversión SAM, una conversión automática de una lambda en una interfaz con un único método abstracto. Actualmente, la conversión SAM no es compatible con las interfaces definidas en Kotlin. En su lugar, debe definir un objeto anónimo que implemente la interfaz:
val obj = object : MyInterface { override fun onLocationMeasured(location: Location) { ... } }La mejor solución es usar un typealias en lugar de su interfaz Java
typealias MyInterface = (Location) -> Unit
fun addLocationHandler(myInterface:MyInterface) { }Regístrelo así:
val myObject = { location -> ...} addLocationHandler(myObject)o incluso más limpio
addLocationHandler { location -> ...}Invocalo así:
myInterface.invoke(location)Las 3 opciones actuales parecen ser:
Al convertir nuestras bibliotecas a Kotlin, en realidad dejamos todas las interfaces en código Java, ya que era más limpio llamar a Java desde Kotlin que a Kotlin desde Kotlin.
si tienes una clase de Java como esta:
recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(), recyclerView, new RecyclerTouchListener.ClickListener() { //Your Code }));deberías convertir este código de Java a Kotlin así:
override fun showJozList (list : List<ResponseGetJuzList.Parameter4>) { adapter.addData(list) jozlist_recycler.addOnItemTouchListener(RecyclerTouchListener( activity , jozlist_recycler , object : RecyclerTouchListener.ClickListener { //Your Code }))convertir interfaz Java :
new RecyclerTouchListener.ClickListener()al estilo de interfaz de Kotlin :
object : RecyclerTouchListener.ClickListenerIntente acceder a su interfaz de esta manera:
object : MyInterface { override fun onSomething() { ... } }Si la interfaz es para un método de escucha de una clase, cambie la definición de la interfaz al tipo de función. Eso hace que el código sea más conciso. Vea lo siguiente.
Clase que contiene definición de oyente
// A class private var mLocationMeasuredListener = (location: Location) -> Unit = {} var setOnLocationMeasuredListener(listener: (location: Location) -> Unit) { mLocationMeasuredListener = listener } // somewhere in A class mLocationMeasuredListener(location)Otra clase
// B class aClass.setOnLocationMeasuredListener { location -> // your code }class YourClass : YourInterface { override fun getTest() = "test" } interface YourInterface { fun getTest(): String } val objectYourClass: YourInterface = YourClass() print(objectYourClass.getTest())La conversión SAM es compatible con las interfaces definidas en Kotlin desde 1.4.0
Antes de Kotlin
1.4.0, podía aplicar conversiones SAM (Método abstracto único) solo cuando trabajaba con métodos Java e interfaces Java de Kotlin. A partir de ahora, también puede utilizar las conversiones SAM para las interfaces de Kotlin. Para hacerlo, marca una interfaz de Kotlin explícitamente como funcional con el modificadorfun.
La conversión SAM se aplica si pasa una lambda como argumento cuando se espera una interfaz con un solo método abstracto como parámetro. En este caso, el compilador convierte automáticamente la lambda en una instancia de la clase que implementa la función de miembro abstracto.
Entonces, el ejemplo en Tu pregunta se verá así:
fun interface MyInterface { fun onLocationMeasured(location: String) } fun main() { val myObj = MyInterface { println(it) } myObj.onLocationMeasured("New York") }