Introducción

En este tema, exploraremos las corrutinas en Kotlin, una característica poderosa para manejar la programación asíncrona de manera eficiente y sencilla. Las corrutinas permiten escribir código asíncrono de manera secuencial, lo que facilita la lectura y el mantenimiento del código.

Conceptos Clave

  1. Corrutinas: Son una forma de realizar tareas asíncronas sin bloquear el hilo principal.
  2. Scope (Alcance): Define el contexto en el que se ejecutan las corrutinas.
  3. Dispatcher (Despachador): Determina en qué hilo o hilos se ejecutará la corrutina.
  4. Job: Representa una unidad de trabajo que se puede cancelar.
  5. Deferred: Es un Job que puede devolver un resultado.

Configuración Inicial

Para usar corrutinas en Kotlin, necesitas agregar la dependencia de corrutinas en tu archivo build.gradle:

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2'

Ejemplo Básico de Corrutina

Lanzar una Corrutina

import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        delay(1000L)
        println("Corrutina!")
    }
    println("Hola,")
}

Explicación

  • runBlocking: Bloquea el hilo principal hasta que todas las corrutinas dentro de él se completen.
  • launch: Inicia una nueva corrutina sin bloquear el hilo actual.
  • delay: Suspende la corrutina durante el tiempo especificado sin bloquear el hilo.

Ejercicio Práctico

Ejercicio 1:

Escribe un programa que lance dos corrutinas. La primera debe imprimir "Primera Corrutina" después de 1 segundo y la segunda debe imprimir "Segunda Corrutina" después de 2 segundos.

Solución:

import kotlinx.coroutines.*

fun main() = runBlocking {
    launch {
        delay(1000L)
        println("Primera Corrutina")
    }
    launch {
        delay(2000L)
        println("Segunda Corrutina")
    }
    println("Inicio")
}

Scope y Dispatcher

Scope

El scope define el contexto de la corrutina. Los scopes más comunes son GlobalScope, CoroutineScope y runBlocking.

Dispatcher

El dispatcher determina en qué hilo se ejecutará la corrutina. Los dispatchers más comunes son:

  • Dispatchers.Default: Utiliza un pool de hilos compartido.
  • Dispatchers.IO: Optimizado para operaciones de entrada/salida.
  • Dispatchers.Main: Utilizado para operaciones en el hilo principal (UI).

Ejemplo con Dispatcher

import kotlinx.coroutines.*

fun main() = runBlocking {
    launch(Dispatchers.Default) {
        println("Default Dispatcher: ${Thread.currentThread().name}")
    }
    launch(Dispatchers.IO) {
        println("IO Dispatcher: ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Main) {
        println("Main Dispatcher: ${Thread.currentThread().name}")
    }
}

Ejercicio Práctico

Ejercicio 2:

Modifica el programa anterior para que cada corrutina imprima un mensaje diferente y se ejecute en un dispatcher diferente.

Solución:

import kotlinx.coroutines.*

fun main() = runBlocking {
    launch(Dispatchers.Default) {
        println("Ejecutando en Default Dispatcher: ${Thread.currentThread().name}")
    }
    launch(Dispatchers.IO) {
        println("Ejecutando en IO Dispatcher: ${Thread.currentThread().name}")
    }
    launch(Dispatchers.Main) {
        println("Ejecutando en Main Dispatcher: ${Thread.currentThread().name}")
    }
}

Job y Deferred

Job

Un Job representa una unidad de trabajo que puede ser cancelada.

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        repeat(1000) { i ->
            println("Job: $i")
            delay(500L)
        }
    }
    delay(1300L)
    println("Cancelando el job")
    job.cancelAndJoin()
    println("Job cancelado")
}

Deferred

Un Deferred es un Job que puede devolver un resultado.

import kotlinx.coroutines.*

fun main() = runBlocking {
    val deferred = async {
        delay(1000L)
        "Resultado"
    }
    println("Esperando el resultado...")
    val result = deferred.await()
    println("Resultado: $result")
}

Ejercicio Práctico

Ejercicio 3:

Escribe un programa que lance un Job que imprima números del 1 al 5 con un retraso de 1 segundo entre cada número. Después de 3 segundos, cancela el Job.

Solución:

import kotlinx.coroutines.*

fun main() = runBlocking {
    val job = launch {
        repeat(5) { i ->
            println("Número: ${i + 1}")
            delay(1000L)
        }
    }
    delay(3000L)
    println("Cancelando el job")
    job.cancelAndJoin()
    println("Job cancelado")
}

Conclusión

En esta sección, hemos aprendido los conceptos básicos de las corrutinas en Kotlin, incluyendo cómo lanzarlas, los diferentes scopes y dispatchers, y cómo manejar Job y Deferred. Las corrutinas son una herramienta poderosa para manejar la programación asíncrona de manera eficiente y legible. En el próximo módulo, exploraremos cómo aplicar estos conceptos en el desarrollo de aplicaciones Android con Kotlin.

© Copyright 2024. Todos los derechos reservados