Estoy trabajando en una biblioteca de Android que contiene algunas vistas. Naturalmente, estas vistas pueden emitir eventos.
Tengo una interfaz llamada (solo para el propósito de esta pregunta) Listener . Si escribiera la biblioteca en Java, las cosas se verían así:
public interface Listener { void onEvent(); } public class SomeView extends FrameLayout { // Some more functions and implementation details public void setListener(Listener l) { ... } } Cuando uso esta vista en una actividad de Kotlin, puedo usar setListener de esta manera:
someViewInstance.setListener { // implementation }Quiero escribir mi biblioteca en Kotlin, pero también podría usarse en código Java, por lo que quiero proporcionar una interfaz para el oyente como una vista normal (como arriba), pero tengo la opción de que el código Kotlin use la función. implementación:
interface Listener { fun onEvent() } cuando trato de usar setListener como arriba en mi actividad de prueba de Kotlin, aparece un error de compilación que dice que la función espera el tipo Listener pero obtuvo () -> Unit .
¿Hay alguna manera de habilitar este tipo de implementación en Kotlin sin tener que crear una nueva función para esto?
Pensé en tener solo una función que recibe () -> Unit pero luego se ve raro en el código Java ( Function1 , etc.).
¡Gracias!
Puede definir su interfaz como se sugiere y también agregar una extensión que permita el uso de una lambda que es más idéntica para el código de Kotlin.
class SomeView { fun setListener(l: Listener) {} } fun SomeView.setListener(l: () -> Unit) = setListener(object : Listener { override fun onEvent() = l() }) En Java, aún podría pasar la implementación de Listener .
Esto se llama conversiones SAM ,
Al igual que Java 8, Kotlin admite conversiones SAM. Esto significa que los literales de funciones de Kotlin se pueden convertir automáticamente en implementaciones de interfaces de Java con un solo método no predeterminado, siempre que los tipos de parámetros del método de interfaz coincidan con los tipos de parámetros de la función de Kotlin.
Pero
Tenga en cuenta que las conversiones SAM solo funcionan para interfaces, no para clases abstractas, incluso si estas también tienen un solo método abstracto.
También tenga en cuenta que esta función solo funciona para la interoperabilidad de Java ; dado que Kotlin tiene tipos de funciones adecuados, la conversión automática de funciones en implementaciones de interfaces de Kotlin es innecesaria y, por lo tanto, no es compatible.
Por lo tanto, no puede escribir un código Kotlin simple para simular esta llamada.
En Java , si escribes un
public interface Listener { void onEvent(); // SAM: Single Abstract Method. Only 1 is allowed }Y tienes un
public class SomeView extends FrameLayout { // skip the constructors public void setListener(Listener listener) { // do something } }Entonces puedes hacer una llamada tan elegante en Kotlin, gracias a la conversión SAM:
SomeView(this).setListener {} // asking a parameter with type () -> Unit for setListener // Then parenthesis of function call can be omitted // setListener function can also accept a parameter with type Listener // by object : Listener {} Pero si convierte ese archivo Java a Kotlin, el código informará un error, debido a la razón mencionada anteriormente. Tienes que implementar una SomeView.setListener(() -> Unit) por ti mismo, por ejemplo
fun SomeView.setListener(l: () -> Unit) { listener = object : Listener{ override fun onEvent() { l() } } }para Kotlin 1.4+. Puede usar la conversión SAM para las funciones de Kotlin si marca una interfaz como una interfaz "funcional":
fun interface Listener { fun onEvent() }