Android KTX   Parte de Android Jetpack.

Android KTX es un conjunto de extensiones de Kotlin que se incluyen con Android Jetpack y otras bibliotecas de Android. Las extensiones KTX proporcionan Kotlin conciso e idiomático a Jetpack, la plataforma de Android y otras APIs. Para ello, esas extensiones aprovechan varias funciones del lenguaje Kotlin, entre las que se incluyen:

  • Funciones de extensión
  • Propiedades de extensión
  • Lambdas
  • Parámetros con nombres
  • Valores predeterminados de parámetros
  • Corrutinas

A modo de ejemplo, cuando trabajes con SharedPreferences, deberás crear un editor antes de realizar modificaciones en los datos de preferencias. También deberás aplicar o confirmar esos cambios cuando termines de editar, como se muestra en el siguiente ejemplo:

sharedPreferences
        .edit()  // create an Editor
        .putBoolean("key", value)
        .apply() // write to disk asynchronously

Las lambdas de Kotlin son ideales para este caso práctico. Te permiten usar un enfoque más conciso, ya que se pasa un bloque de código para ejecutarse después de crear el editor, lo que permite que se ejecute el código y, luego, que la API de SharedPreferences aplique los cambios automáticamente.

Este es un ejemplo de una de las funciones de Android KTX Core, SharedPreferences.edit, que agrega una función de edición a SharedPreferences. Esta función incluye una marca boolean opcional como su primer argumento que indica si confirmar o aplicar los cambios. También recibe una acción para realizar en el editor SharedPreferences en forma de lambda.

// SharedPreferences.edit extension function signature from Android KTX - Core
// inline fun SharedPreferences.edit(
//         commit: Boolean = false,
//         action: SharedPreferences.Editor.() -> Unit)

// Commit a new value asynchronously
sharedPreferences.edit { putBoolean("key", value) }

// Commit a new value synchronously
sharedPreferences.edit(commit = true) { putBoolean("key", value) }

El llamador puede elegir confirmar o aplicar los cambios. La lambda action es una función de extensión anónima de SharedPreferences.Editor que devuelve Unit, como lo indica su firma. Por eso, dentro del bloque, puedes realizar el trabajo de forma directa en el SharedPreferences.Editor.

Por último, la firma SharedPreferences.edit() contiene la palabra clave inline. Esta palabra clave le dice al compilador Kotlin que debe copiar y pegar (o intercalar) el código de bytes compilado para la función cada vez que se utiliza. Esto evita la sobrecarga que se genera al crear instancias de una nueva clase por cada action cada vez que se llama a esa función.

Este patrón de pasar código con lambdas, aplicar valores predeterminados confidenciales que pueden anularse y agregar estos comportamientos a las APIs existentes mediante funciones de extensión inline es típico de las mejoras proporcionadas por la biblioteca de Android KTX.

Cómo usar Android KTX en tu proyecto

Para comenzar a usar Android KTX, agrega la siguiente dependencia al archivo build.gradle de tu proyecto:

Groovy

repositories {
    google()
}

Kotlin

repositories {
    google()
}

Módulos de AndroidX

Android KTX está organizado en módulos, y cada módulo contiene uno o más paquetes.

Debes incluir una dependencia para el artefacto de cada módulo en el archivo build.gradle de tu app. Recuerda agregar el número de versión al artefacto. Puedes encontrar los números de versión más recientes en la sección correspondiente de cada artefacto de este tema.

Android KTX incluye un módulo principal único que proporciona extensiones de Kotlin para las APIs de frameworks comunes y varias extensiones específicas de dominio.

A excepción del módulo principal, todos los artefactos del módulo KTX reemplazan la dependencia subyacente de Java en tu archivo build.gradle. Por ejemplo, puedes reemplazar una dependencia androidx.fragment:fragment por androidx.fragment:fragment-ktx. Esta sintaxis ayuda a administrar mejor las versiones y no agrega requisitos adicionales para declarar dependencias.

Core KTX

El módulo Core KTX ofrece extensiones para bibliotecas comunes que forman parte del marco de trabajo de Android. Esas bibliotecas no tienen dependencias basadas en Java que debas agregar a build.gradle.

Para incluir este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.core:core-ktx:1.13.1"
}

Kotlin

dependencies {
    implementation("androidx.core:core-ktx:1.13.1")
}

Esta es una lista de los paquetes que se incluyen en el módulo Core KTX:

Collection KTX

Las extensiones de Collection contienen funciones de utilidad para trabajar con las bibliotecas de colección eficientes en cuanto a memoria de Android, como ArrayMap, LongSparseArray, LruCache y otras.

Para usar este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.collection:collection-ktx:1.4.5"
}

Kotlin

dependencies {
    implementation("androidx.collection:collection-ktx:1.4.5")
}

Las extensiones de la colección aprovechan la sobrecarga del operador de Kotlin para simplificar la concatenación de colecciones, entre otras tareas, como se muestra en el siguiente ejemplo:

// Combine 2 ArraySets into 1.
val combinedArraySet = arraySetOf(1, 2, 3) + arraySetOf(4, 5, 6)

// Combine with numbers to create a new sets.
val newArraySet = combinedArraySet + 7 + 8

Fragment KTX

El módulo Fragment KTX proporciona varias extensiones para simplificar la API del fragmento.

Para incluir este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.fragment:fragment-ktx:1.6.2"
}

Kotlin

dependencies {
    implementation("androidx.fragment:fragment-ktx:1.6.2")
}

Con el módulo Fragment KTX, puedes simplificar las transacciones de fragmento con lambdas, por ejemplo:

fragmentManager().commit {
   addToBackStack("...")
   setCustomAnimations(
           R.anim.enter_anim,
           R.anim.exit_anim)
   add(fragment, "...")
}

También puedes vincular a un ViewModel en una línea si utilizas los delegados de propiedad viewModels y activityViewModels:

// Get a reference to the ViewModel scoped to this Fragment
val viewModel by viewModels<MyViewModel>()

// Get a reference to the ViewModel scoped to its Activity
val viewModel by activityViewModels<MyViewModel>()

Lifecycle KTX

Lifecycle KTX define un LifecycleScope para cada objeto Lifecycle. Se cancelan todas las corrutinas iniciadas en este alcance cuando se destruye el Lifecycle. Puedes acceder al CoroutineScope del Lifecycle desde las propiedades lifecycle.coroutineScope o lifecycleOwner.lifecycleScope.

Para incluir este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.8.7"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.8.7")
}

En el siguiente ejemplo, se muestra cómo usar lifecycleOwner.lifecycleScope para crear texto procesado previamente de forma asíncrona:

class MyFragment: Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewLifecycleOwner.lifecycleScope.launch {
            val params = TextViewCompat.getTextMetricsParams(textView)
            val precomputedText = withContext(Dispatchers.Default) {
                PrecomputedTextCompat.create(longTextContent, params)
            }
            TextViewCompat.setPrecomputedText(textView, precomputedText)
        }
    }
}

LiveData KTX

Cuando usas LiveData, es posible que debas calcular valores de forma asíncrona. Por ejemplo, es posible que quieras recuperar las preferencias de un usuario y entregarlas a tu IU. En estos casos, LiveData KTX proporciona una función del compilador de liveData que llama a una función suspend y entrega el resultado como un objeto LiveData.

Para incluir este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.8.7"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-livedata-ktx:2.8.7")
}

En el siguiente ejemplo, loadUser() es una función de suspensión declarada en otro lugar. Puedes usar la función del compilador de liveData para llamar a loadUser() de forma asíncrona y, luego, usar emit() para emitir el resultado:

val user: LiveData<User> = liveData {
    val data = database.loadUser() // loadUser is a suspend function.
    emit(data)
}

Si quieres obtener más información para usar las corrutinas con LiveData, consulta Cómo usar las corrutinas de Kotlin con componentes optimizados para ciclos de vida.

Cada componente de la biblioteca de Navigation tiene su propia versión de KTX que adapta la API para que sea más breve e idiomática para Kotlin.

Para incluir estos módulos, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.navigation:navigation-runtime-ktx:2.7.5"
    implementation "androidx.navigation:navigation-fragment-ktx:2.7.5"
    implementation "androidx.navigation:navigation-ui-ktx:2.7.5"
}

Kotlin

dependencies {
    implementation("androidx.navigation:navigation-runtime-ktx:2.7.5")
    implementation("androidx.navigation:navigation-fragment-ktx:2.7.5")
    implementation("androidx.navigation:navigation-ui-ktx:2.7.5")
}

Utiliza las funciones de extensión y la delegación de propiedades para acceder a los argumentos de destino y navegar a los destinos, como se muestra en el siguiente ejemplo:

class MyDestination : Fragment() {

    // Type-safe arguments are accessed from the bundle.
    val args by navArgs<MyDestinationArgs>()

    ...
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        view.findViewById<Button>(R.id.next)
            .setOnClickListener {
                // Fragment extension added to retrieve a NavController from
                // any destination.
                findNavController().navigate(R.id.action_to_next_destination)
            }
     }
     ...

}

Palette KTX

El módulo Palette KTX ofrece la compatibilidad idiomática de Kotlin para trabajar con paletas de colores.

Para usar este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.palette:palette-ktx:1.0.0"
}

Kotlin

dependencies {
    implementation("androidx.palette:palette-ktx:1.0.0")
}

Por ejemplo, cuando trabajas con una instancia Palette, puedes recuperar la muestra selected de un target específico si utilizas el operador get ([ ]):

val palette = Palette.from(bitmap).generate()
val swatch = palette[target]

Reactive Streams KTX

El módulo Reactive Streams KTX te permite crear una transmisión LiveData observable desde un publicador ReactiveStreams.

Para incluir este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.7"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-reactivestreams-ktx:2.8.7")
}

Como ejemplo, supone una base de datos con una pequeña lista de usuarios. En tu app, carga la base de datos en la memoria y, luego, muestra los datos del usuario en tu IU. Para lograrlo, puedes usar RxJava. El componente Room de Jetpack puede recuperar la lista de usuarios como un Flowable. En este caso, también debes administrar la suscripción del publicador de Rx durante la vigencia de tu fragmento o actividad.

Sin embargo, con LiveDataReactiveStreams, puedes beneficiarte de RxJava y su amplio conjunto de operadores y capacidades de programación de trabajo al mismo tiempo que trabajas con la simplicidad de LiveData, como se muestra en el siguiente ejemplo:

val fun getUsersLiveData() : LiveData<List<User>> {
    val users: Flowable<List<User>> = dao.findUsers()
    return LiveDataReactiveStreams.fromPublisher(users)
}

Room KTX

Las extensiones de Room agregan compatibilidad para corrutinas destinada a las transacciones de base de datos.

Para usar este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.room:room-ktx:2.6.1"
}

Kotlin

dependencies {
    implementation("androidx.room:room-ktx:2.6.1")
}

Estos son algunos ejemplos en los que Room ahora usa corrutinas. El primer ejemplo usa una función suspend para devolver una lista de objetos User, mientras que el segundo utiliza Flow de Kotlin para devolver la lista User de forma asíncrona. Ten en cuenta que, cuando usas Flow, también recibes notificaciones de cualquier cambio en las tablas que consultas.

@Query("SELECT * FROM Users")
suspend fun getUsers(): List<User>

@Query("SELECT * FROM Users")
fun getUsers(): Flow<List<User>>

SQLite KTX

Las extensiones de SQLite unen el código relacionado con SQL en las transacciones, lo que elimina una gran cantidad de código estándar.

Para usar este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.sqlite:sqlite-ktx:2.4.0"
}

Kotlin

dependencies {
    implementation("androidx.sqlite:sqlite-ktx:2.4.0")
}

El siguiente es un ejemplo de cómo usar la extensión transaction para realizar una transacción de base de datos:

db.transaction {
    // insert data
}

ViewModel KTX

La biblioteca de ViewModel KTX ofrece una función viewModelScope() que facilita el lanzamiento de corrutinas desde tu ViewModel. El CoroutineScope está vinculado a Dispatchers.Main y se cancela automáticamente cuando se borra el ViewModel. Puedes usar viewModelScope() en lugar de crear un nuevo alcance para cada ViewModel.

Para incluir este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7"
}

Kotlin

dependencies {
    implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.7")
}

A modo de ejemplo, la siguiente función viewModelScope() lanza una corrutina que realiza una solicitud de red en un subproceso en segundo plano. La biblioteca maneja toda la configuración y la liberación del alcance correspondiente:

class MainViewModel : ViewModel() {
    // Make a network request without blocking the UI thread
    private fun makeNetworkRequest() {
        // launch a coroutine in viewModelScope
        viewModelScope.launch  {
            remoteApi.slowFetch()
            ...
        }
    }

    // No need to override onCleared()
}

WorkManager KTX

WorkManager KTX proporciona compatibilidad óptima con corrutinas.

Para incluir este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "androidx.work:work-runtime-ktx:2.9.0"
}

Kotlin

dependencies {
    implementation("androidx.work:work-runtime-ktx:2.9.0")
}

En lugar de extender Worker, deberías extender CoroutineWorker, que tiene una API levemente diferente. Por ejemplo, si quieres compilar un CoroutineWorker simple para realizar algunas operaciones de red, debes hacer lo siguiente:

class CoroutineDownloadWorker(context: Context, params: WorkerParameters)
        : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result = coroutineScope {
        val jobs = (0 until 100).map {
            async {
                downloadSynchronously("https://www.google.com")
            }
        }

        // awaitAll will throw an exception if a download fails, which
        // CoroutineWorker will treat as a failure
        jobs.awaitAll()
        Result.success()
    }
}

Para obtener más información sobre el uso de CoroutineWorker, consulta Cómo ejecutar subprocesos en CoroutineWorker.

WorkManager KTX también agrega funciones de extensión a Operations y ListenableFutures para suspender la corrutina actual.

El siguiente es un ejemplo que suspende el Operation que devuelve enqueue():

// Inside of a coroutine...

// Run async operation and suspend until completed.
WorkManager.getInstance()
        .beginWith(longWorkRequest)
        .enqueue().await()

// Resume after work completes...

Otros módulos KTX

También puedes incluir módulos KTX adicionales fuera de AndroidX.

Firebase KTX

Algunos de los SDKs de Firebase para Android tienen bibliotecas de extensión de Kotlin que te permiten escribir código idiomático de Kotlin cuando usas Firebase en tu app. Para obtener más información, consulta los siguientes temas:

Google Maps Platform KTX

Hay extensiones KTX disponibles para los SDKs de Android de Google Maps Platform que te permiten aprovechar varias funciones del lenguaje Kotlin, como funciones de extensión, parámetros con nombre y argumentos predeterminados, declaraciones de desestructuración y corrutinas. Para obtener más información, consulta los siguientes temas:

Play Core KTX

Play Core KTX admite las corrutinas de Kotlin para solicitudes por única vez y Flow para supervisar las actualizaciones de estado cuando agrega funciones de extensión a SplitInstallManager y AppUpdateManager en la biblioteca de Play Core.

Para incluir este módulo, agrega lo siguiente al archivo build.gradle de tu app:

Groovy

dependencies {
    implementation "com.google.android.play:core-ktx:1.8.1"
}

Kotlin

dependencies {
    implementation("com.google.android.play:core-ktx:1.8.1")
}

El siguiente es un ejemplo de un Flow de supervisión de estado:

// Inside of a coroutine...

// Request in-app update status updates.
manager.requestUpdateFlow().collect { updateResult ->
    when (updateResult) {
        is AppUpdateResult.Available -> TODO()
        is AppUpdateResult.InProgress -> TODO()
        is AppUpdateResult.Downloaded -> TODO()
        AppUpdateResult.NotAvailable -> TODO()
    }
}

Más información

Para obtener más información sobre Android KTX, consulta el video de DevBytes.

Para informar un problema o sugerir una función, usa la herramienta de seguimiento de errores de Android KTX.