Delegación de propiedades en Kotlin: asigna valores en Android sin tener el contexto (KDA 15)
Antonio Leiva

Como hemos visto en artículos anteriores, las propiedades necesitan un valor por defecto, no se pueden declarar sin asignarles un valor.

Esto es un problema, porque imagina que quieres almacenar una vista en una property. Como este código es ejecuta durante la creación del objeto, no puedes acceder al contexto en ese momento.

¿Qué puedes hacer?

Si quieres aprender cuál es la situación de Kotlin en el mercado, por qué debes aprenderlo y los primeros pasos para que veas lo fácil que es, he preparado un training gratuito de hora y media al que puedes unirte haciendo click aquí

Training Revienta tu productividad en Android con Kotlin

Delegación de propiedades: delega el valor de una property en otro objeto

La delegación de propiedades utilizará otro objeto que es capaz de devolver un resultado cuando se llame al get y al set (en caso de que se utilice var).

En un mundo en el que no tenemos control sobre la creación de muchos objetos, como es el framework de Android, esta delegación nos va a salvar la vida en muchos casos.

Te voy a mostrar tres ejemplos que a mí me resultan muy útiles en Android

Setear el valor de una vista en una property

Para esto tenemos dos opciones utilizando delegación, y evitando usar null, (algo muy poco recomendado).

La primera me gusta menos, porque obliga a utilizar var para una propiedad que podría ser inmutable, y además es menos seguro.

Con la palabra reservada lateinit le decimos a esa property que no va a estar vacía, pero que todavía no tenemos su valor final:

lateinit var textView:TextView

En el onCreate podemos entonces asignarle el valor definitivo:

setContentView(R.layout.activity_main)
textView = findView(R.id.welcomeMessage)
toast(textView.text)

Esto en realidad no es un delegado, aunque hace la misma operación que el delegado notNull, que quedó relegado en favor de este primero.

La segunda opción es mucho más elegante. Consiste en usar el delegado lazy, que no ejecutará el código que se le indique hasta que no se llame por primera vez a la property:

val textView by lazy { findView(R.id.welcomeMessage) }

El findView no se ejecutará hasta que no se llame al get del textView por primera vez. Es más seguro porque no se puede modificar el valor por error, y no nos obliga a acordarnos de setearlo tras el setContentView.

En el momento en que hagamos:

toast(textView.text)

Se ejecutará el código de forma lazy.

Como ves, la forma de delegar es utilizando la palabra reservada by.

Vamos a ver otro ejemplo

Notificar cambios en un adapter

En un adapter podemos tener una property items que cada vez que se setee lance automáticamente una actualización del adapter:

var items: List by Delegates.observable(emptyList()) {
    p, old, new -> notifyDataSetChanged()
}

Simplemente establece un valor inicial, y posteriormente llama a la función que se define tras cada modificación.

En este caso solo estoy llamando a notifyDataSetChanged, pero como ves, la función recibe los valores antiguos y nuevos, así que técnicamente podrías comprobar cuáles son los cambios y actualizar sólo la diferencia.

Declarar el grafo de Dagger de forma lazy

Es otra de la situaciones en las que he encontrado esta funcionalidad muy útil.

Volviendo a lazy, lo puedes utilizar para declarar el component de la aplicación durante la declaración de la property:

val component: AppComponent by lazy { 
    DaggerAppComponent
            .builder()
            .appModule(AppModule(this))
            .build() 
}

De esta forma no necesitas utilizar lateinit, y la propiedad se vuelve inmutable.

Puedes hacer lo mismo si estás utilizando subcomponents en las actividades:

class HomeActivity : AppCompatActivity(), HomePresenter.View {
    val component by lazy { app.component.plus(HomeModule(this)) }
    ...
}

Conclusión

La declaración de propiedades te ayudará a hacer las propiedades mucho más potentes y simplificar y reutilizar código.

Aquí sólo hemos visto propiedades estándar de la librería de Kotlin, pero puedes crear las tuyas propias.

Por ejemplo en el libro tengo una implementada que almacena y recupera datos de las SharedPreference.

¿Te gustaría comenzar hoy a dar el siguiente paso? Te recomiendo que entres en mi training gratuito aquí.

Quizá también te interese…

Kotlin 1.5.0 : Las 5 novedades que puedes empezar a usar hoy

Kotlin 1.5.0 : Las 5 novedades que puedes empezar a usar hoy

Kotlin 1.5.0 ya está aquí, y como siempre trae una serie de novedades que te van a interesar muchísimo. Cabe destacar que a partir de ahora, de acuerdo las nuevas versiones de Kotlin se lanzarán cada 6 meses, independientemente de las nuevas funcionalidades que...

¿Qué es Kotlin y para qué sirve?

¿Qué es Kotlin y para qué sirve?

Kotlin es un lenguaje de programación de código abierto creado por JetBrains que se ha popularizado gracias a que se puede utilizar para programar aplicaciones Android. Pero si has llegado hasta aquí pensando que Kotlin solo se puede usar en Android, lo que te voy a...

2 formas de recolectar Flows en la UI que SÍ funcionan

2 formas de recolectar Flows en la UI que SÍ funcionan

En la serie de artículos sobre Programación Reactiva con Flow hemos visto muchos conceptos, y hemos aprendido cómo aplicarlos al desarrollo Android. Pero hay algo que no hemos hecho del todo bien. Esto es la recolección de Flows desde la Activity (o el Fragment, en...

2 Comentarios

  1. Luis Angel

    Hola!
    Realmente encuentro muy útiles estas funciones, porque si me he topado muchas veces con la limitación de no poder inicializar un final en Java.
    Sólo tengo algunas dudas:

    ¿Las properties val no pueden usar lateinit?

    ¿Cómo sabes a qué se refiere cada parámetro en las lambdas que recibes? Cómo en el adapter, no se bien para que es p, y así podría pasar en otras funciones.

    Gracias

    Responder

Enviar un comentario

Los datos personales que proporciones a través de este formulario quedarán registrados en un fichero de Antonio Leiva Gordillo, con el fin de gestionar los comentarios que realizas en este blog. La legitimación se realiza a través del consentimiento de la parte interesada. Si no se acepta, no podrás comentar en este blog. Los datos que proporciona solo se utilizan para evitar el correo no deseado y no se usarán para nada más. Puede ejercer los derechos de acceso, rectificación, cancelación y oposición en contacto@devexperto.com.

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Acepto la política de privacidad *