Coroutine Builder — funciones de Kotlin Coroutines que crean y lanzan corrutinas, definiendo cómo se ejecutan. Los constructores launch, async, runBlocking y produce cubren diferentes escenarios: desde tareas en segundo plano hasta cómputos paralelos con devolución de resultados. Según JetBrains, 2024, Coroutine Builder es la base del modelo de corrutinas, proporcionando concurrencia estructurada y gestión del ciclo de vida.
Puntos clave
Coroutine Builder es una función de extensión de Kotlin que toma un CoroutineScope y un bloque suspend, creando y lanzando una nueva corrutina. Cada constructor define cómo se ejecutará la corrutina: con o sin devolución de resultado, con bloqueo de hilo o asíncronamente. Los constructores son los puntos de entrada al modelo de corrutinas del lenguaje.
Todos los constructores trabajan a través de CoroutineScope, que gestiona el ciclo de vida de las corrutinas hijas. Cuando se cancela un scope, todas las corrutinas lanzadas a través de él se cancelan automáticamente — este es el principio de concurrencia estructurada. Este enfoque previene fugas de corrutinas y garantiza una finalización predecible.
import kotlinx.coroutines.*
fun main() = runBlocking {
// Los builders se ejecutan dentro de CoroutineScope
val job = launch {
delay(1000L)
println("¡Mundo!")
}
println("Hola,")
job.join()
}
Kotlin proporciona cuatro constructores de corrutinas incorporados: launch, async, runBlocking y produce. Cada uno tiene su propio tipo de retorno y área de aplicación. Para desarrollo móvil Android, los principales son launch y async — funcionan de manera no bloqueante y se integran con componentes arquitectónicos.
| Constructor | Tipo de retorno | Bloqueo de hilo | Escenario |
|---|---|---|---|
| launch | Job | No | Tareas fire-and-forget |
| async | Deferred<T> | No | Cómputos paralelos |
| runBlocking | T | Sí | Tests, función main |
| produce | ReceiveChannel<E> | No | Transmisión (obsoleto) |
Cada constructor acepta parámetros adicionales: CoroutineStart (estrategia de lanzamiento), CoroutineContext (despachador, excepciones) y un bloque de código nombrado. Por defecto, la corrutina se inicia inmediatamente (CoroutineStart.DEFAULT).
launch es el constructor más utilizado en desarrollo Android. Lanza una corrutina que no devuelve un resultado, y devuelve un objeto Job para gestionar su ciclo de vida. Es la elección ideal para operaciones que solo necesitan un efecto secundario: guardar en base de datos, enviar analíticas, actualizar la UI.
El constructor launch acepta CoroutineScope, un CoroutineContext opcional y un bloque suspend. El Job devuelto permite cancelar la corrutina, esperar su finalización o verificar su estado.
val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())
val job: Job = scope.launch(CoroutineStart.LAZY) {
val data = fetchFromNetwork()
saveToDatabase(data)
}
job.start()
job.join()
El parámetro CoroutineStart.LAZY aplaza la ejecución hasta una llamada explícita a start() o join(). Esto es útil para inicialización diferida y ejecución condicional. Para ejecución inmediata estándar se usa CoroutineStart.DEFAULT o se omite el parámetro.
async es un constructor que devuelve Deferred<T> — una promesa asíncrona de un resultado. Llamar a await() suspende la corrutina hasta obtener el resultado, sin bloquear el hilo. Es el mecanismo principal para tareas paralelas en corrutinas Kotlin.
async es especialmente efectivo cuando necesitas ejecutar múltiples operaciones independientes simultáneamente. A diferencia de las llamadas secuenciales a funciones suspend, async lanza corrutinas en paralelo, reduciendo el tiempo total de ejecución.
suspend fun fetchUserData(): UserData {
val deferred1 = CoroutineScope(Dispatchers.IO).async { api.getProfile() }
val deferred2 = CoroutineScope(Dispatchers.IO).async { api.getSettings() }
val deferred3 = CoroutineScope(Dispatchers.IO).async { api.getNotifications() }
return UserData(
profile = deferred1.await(),
settings = deferred2.await(),
notifications = deferred3.await()
)
}
Deferred hereda de Job, por lo que async soporta todas las operaciones del ciclo de vida: cancelación, espera de finalización, manejo de excepciones. Cuando se cancela un scope, las corrutinas Deferred hijas se cancelan automáticamente.
runBlocking es el único constructor que bloquea el hilo actual hasta que la corrutina finaliza. Crea un nuevo CoroutineScope y lanza la corrutina pasada, bloqueando el hilo llamante. Se usa en puntos de entrada main(), en tests y al integrar con código bloqueante.
runBlocking está justificado en tres escenarios: el punto de entrada de la aplicación (main), tests unitarios de funciones suspend y la integración con bibliotecas basadas en callbacks donde no se puede usar suspend. En código Android de producción, usar runBlocking en el hilo principal no está recomendado.
class CoroutineTest {
@Test
fun `test suspend function`() = runBlocking {
val result = mySuspendFunction()
assertEquals("expected", result)
}
}
Para tests se recomienda usar kotlinx-coroutines-test con TestCoroutineDispatcher en lugar de runBlocking — esto proporciona control del tiempo y evita bloqueos en el entorno de pruebas.
La elección del Coroutine Builder depende del resultado devuelto y del escenario de ejecución. Si la operación no requiere devolver datos — usa launch. Si necesitas el resultado de una operación asíncrona — usa async. runBlocking solo debe usarse como puente, y reemplaza produce por Flow para flujos reactivos.
En proyectos Android que usan Kotlin Coroutines, el par principal de constructores son launch y async. launch se usa en ViewModel y UseCases para lanzar corrutinas, mientras que async se usa para solicitudes paralelas a la red o base de datos. Las bibliotecas modernas (Ktor, Room) ya soportan funciones suspend, lo que minimiza la necesidad de uso directo de async.
Preguntas frecuentes
launch devuelve Job y no devuelve un resultado de ejecución, mientras que async devuelve Deferred<T> — un objeto del que se puede obtener el resultado mediante await(). launch se usa para operaciones fire-and-forget, async para tareas que devuelven datos.
No se recomienda. runBlocking en el hilo principal causa ANR y bloquea la UI. Usa lifecycleScope.launch dentro de Activity y Fragment — es una solución incorporada sin bloqueos.
El constructor launch devuelve un objeto Job, que permite controlar el ciclo de vida de la corrutina: cancelar (cancel), esperar finalización (join), verificar estado (isActive, isCompleted, isCancelled).
Deferred<T> es una promesa asíncrona de un resultado, devuelta por el constructor async. Hereda de Job y añade métodos await() para obtener el resultado, getCompleted() para acceso no bloqueante y getCompletionExceptionOrNull() para verificar excepciones.
Usa el parámetro CoroutineStart.LAZY: scope.launch(start = CoroutineStart.LAZY) { ... }. Luego llama a job.start() o job.join() para la ejecución real. Esto es útil para inicialización diferida y ejecución condicional de corrutinas.
Resumen
Desarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también