## Corrutinas en Android
Las **corrutinas** son un patrón de diseño de **simultaneidad** que se utiliza en **Android** para simplificar el código asíncrono. A continuación, se presentan los aspectos clave:
1. **¿Qué son las corrutinas?**
- Las corrutinas son una solución recomendada para la programación asíncrona.
- Permiten ejecutar tareas de forma simultánea sin bloquear el subproceso principal.
- Proporcionan ligereza y ahorran memoria al usar la suspensión en lugar del bloqueo.
- Se integran con Jetpack y otras bibliotecas.
2. **Beneficios:**
- **Ligereza**: Puedes ejecutar muchas corrutinas en un solo subproceso.
- **Menos fugas de memoria**: Usa la simultaneidad estructurada para ejecutar operaciones dentro de un alcance.
- **Compatibilidad con cancelación incorporada**: La cancelación se propaga automáticamente entre las corrutinas.
- **Integración con Jetpack**: Muchas bibliotecas de Jetpack ofrecen soporte completo para corrutinas.
3. **Ejemplo:**
- Supongamos que necesitas realizar una solicitud de red en tu app.
- Con las corrutinas, puedes mantener el subproceso principal desbloqueado mientras se realiza la solicitud.


Además: las corrutinas te permiten escribir código más limpio y conciso.
## Comencemos la aplicación de ejemplo
Comenzamos con una aplicación vacía, creamos una columna que servirá solo para colocar un botón que se encargará de simular la llamada a una rutina.
```
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
CorrutinasTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Content()
}
}
}
}
}
@Composable
fun Content(){
Column (
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
BotonColor()
Text(text = "")
Button(onClick = { /*TODO*/ }) {
Text ("Llamar API")
}
}
}
@Composable
fun BotonColor() {
var color by remember { mutableStateOf(false)}
Button(onClick = { color=!color }, colors = ButtonDefaults.buttonColors(
containerColor = if(color) Color.Blue else Color.Red
)) {
Text(text = "Cambiar color")
}
}
```
Como ven lo único que hemos hecho es un botón de cambia de color y otro que va a llamar a una API.

Cuál es el objetivo?
- Vamos a hacer que haya cambios en la interface mientras llamamos a una API.
- Interrumpiremos el mainActivity de manera consciente para evitar problemas con el rendimiento general del programa
Podríamos crear las corrutinas directamente en las activities pero lo normal es usarlas dentro de un modelo ViewModel, vamos a ello...Creamos una clase MainViewModel.
```
class MainViewModel: ViewModel() {
var resultState by mutableStateOf("")
fun bloquearApp(){
Thread.sleep(5000)
resultState="Respuesta de la API"
}
}
```
Como ven hemos creado un atributo que es resultState donde guardaremos una string y hemos creado un método que utiliza el objeto Thread, si vamos a la descripción leemos:
> A thread is a thread of execution in a program. The Java Virtual Machine allows an application to have multiple threads of execution running concurrently.
> Every thread has a priority. Threads with higher priority are executed in preference to threads with lower priority. Each thread may or may not also be marked as a daemon. When code running in some thread creates a new Thread object, the new thread has its priority initially set equal to the priority of the creating thread, and is a daemon thread if and only if the creating thread is a daemon.
> When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:
> The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.
> All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.
> There are two ways to create a new thread of execution. One is to declare a class to be a subclass of Thread. This subclass should override the run method of class Thread. An instance of the subclass can then be allocated and started.
Creo que hay una bonita asignatura donde dan hilos y su uso en profundidad, por lo que sólo nos centraremos en la utilidad práctica para que nuestras aplicaciones móviles sean más rápidas y menos proclives al fallo.

Incluimos la siguiente linea en el onCreate del MainActivity
` val viewModel: MainViewModel by viewModels()`
En el content, además de pasar el viewModel (tanto en el composable como en la llamada) vamos a hacer que el botón muestre el resultState y vamos a llamar a bloqueoApp
```
`@Composable
fun Content(viewModel: MainViewModel){
Column (
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
BotonColor()
Text(text = viewModel.resultState)
Button(onClick = {viewModel.bloquearApp()}) {
Text ("Llamar API")
}
}
}
```
Ejecutamos y vemos que si pulsamos el botón de "Cambiar Color" cambia de color y ya, pero si llamamos a "llamar Api" que simula una respuesta lenta, si le seguimos dando a cambiar color vemos que la interface está bloqueada, pero cuando la supuesta api responde veremos que se cierra la aplicación. La aplicación tenía demasiadas órdenes pendientes y no ha sabido responder.
Esto lo debemos evitar, y el caso es que suele pasar cuando hay llamadas a procesos lentos como las llamadas a base de datos!
Cómo podemos evitar esto, metiendo el proceso lento de Llamar Api, en una corrutina de tal manera que no bloquee nuestra interfaz.
En el MainViewModel vamos a crear una función fetchData y ahí le decimos que vamos a lanzar un Dispatcher ya los vimos en la diapositiva y como vimos, al ser uno de consulta de bases de datos vamos a elegir el IO

Quedaría como sigue:
```
fun fetchData(){
viewModelScope.launch {
val result = withContext( Dispatchers.IO){
delay(5000)
"Respuesta de la APi"
}
resultState=result
}
}
```
En el Content del mainActivity el botón en lugar de llmar a bloquearApp llamará ahora al fetchData y ejecutamos de nuevo la aplicación.
Verás cómo puedes seguir usando la interface y pulsar el botón sin problemas mientras se espera a que la consulta a la API devuelva valores.
Lee más sobre corrutinas:
https://developer.android.com/kotlin/coroutines?hl=es-419
## Bloque try-catch en corrutinas
Crearemos bloques try-catch que ya conocen de java y además manejaremos funciones suspend que son una característica clave de las corrutinas en Kotlin. Estas funciones permiten que la ejecución se suspenda y se reanude, lo que es especialmente útil para realizar operaciones asíncronas o de larga duración sin bloquear el hilo principal.
### ¿Qué hace una función suspend?
- Una función marcada como suspend puede liberar voluntariamente el control de vuelta al llamador.
- A diferencia de las funciones regulares, que se ejecutan secuencialmente, las funciones suspend pueden detenerse y reanudarse más tarde desde donde se quedaron.
- Las corutinas utilizan estas funciones para realizar tareas asíncronas sin bloquear el hilo principal.
Puedes profundizar más en los conceptos avanzados de los tutoriales de Android:
https://developer.android.com/kotlin/coroutines/coroutines-adv?hl=es-419
O seguir este curso de Medium:
https://medium.com/kotlin-en-android/coroutines-con-kotlin-introducci%C3%B3n-a68f5eeee6a8
Pero como siempre, se entiende todo mejor con un ejemplo!
Vamos a crear una función tipo suspend que llame a nuestra api ficticia.
Estas funciones suspend sólo pueden funcionar dentro de una corrutina o en otra función suspend.
En nuestro MainViewModel vamos a hacer que al llamar a nuestra API se muestre un mensaje de "isLoading" y que si hay algún error lance una excepción. Para ello modificamos un poco el código:
```
class MainViewModel: ViewModel() {
var resultState by mutableStateOf("")
var isLoading by mutableStateOf(false )
fun fetchData(){
viewModelScope.launch {
try{
isLoading=true
llamarApi()
} catch (e:Exception){
println("Error ${e.message}")
} finally {
isLoading= false
}
}
}
private suspend fun llamarApi(){
val result = withContext( Dispatchers.IO){
delay(5000)
"Respuesta de la APi"
}
resultState=result
}
```
En el mainActivity cambiamos el Content para que muestre una barra de progreso mientras el isLoading sea true.
```
@Composable
fun Content(viewModel: MainViewModel){
Column(
verticalArrangement= Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
){
BotonColor()
if (viewModel.isLoading){
CircularProgressIndicator()
}else {
Text(text=viewModel.resultState)
}
Button(onClick = { viewModel.fetchData() }) {
Text("LLamar API")
}
}
}
```
## Otro ejemplo
Está claro que mientras no conectemos con una base de datos real y no vemos efectivamente cómo hay muchísimas funciones que no se pueden llamar de manera secuencial no lo veremos claro, pero por ahora vamos a ir haciendo ejemplos que abren la mente a cómo debemos manejar el asincronismo en Android con Kotlin (una de las maneras, hay más!!)
Pues bien vamos a crear un dataClass como sigue:
```
data class ItemsModel(
val id: Int= 0,
val name: String=""
)
```
Y el ItemsViewModel para manejarlo:
```
class ItemsViewModel:ViewModel() {
var itemList= mutableStateListOf(ItemsModel())
private set
var isLoading by mutableStateOf(false)
private set
fun fetchData(){
viewModelScope.launch {
try{
isLoading=true
llamarApi()
} catch (e:Exception){
println("Error ${e.message}")
} finally {
isLoading= false
}
}
}
private suspend fun llamarApi(){
val result= withContext(Dispatchers.IO){
delay(5000)
listOf(
ItemsModel(1, "Elemento 1"), ItemsModel(2, "Elemento 2"), ItemsModel(3, "Elemento 3"), ItemsModel(4, "Elemento 4"), ItemsModel(5, "Elemento 5"),
ItemsModel(6, "Elemento 6"), ItemsModel(7, "Elemento 7"), ItemsModel(8, "Elemento 8"), ItemsModel(9, "Elemento 9"), ItemsModel(10, "Elemento 10"),
ItemsModel(11, "Elemento 11"), ItemsModel(12, "Elemento 12"), ItemsModel(13, "Elemento 13"), ItemsModel(14, "Elemento 14"), ItemsModel(15, "Elemento 15"),
ItemsModel(16, "Elemento 16"), ItemsModel(17, "Elemento 17"), ItemsModel(18, "Elemento 18"), ItemsModel(19, "Elemento 19"), ItemsModel(20, "Elemento 20"),
ItemsModel(21, "Elemento 21"), ItemsModel(22, "Elemento 22"), ItemsModel(23, "Elemento 23"), ItemsModel(24, "Elemento 24"), ItemsModel(25, "Elemento 25"),
ItemsModel(26, "Elemento 26"), ItemsModel(27, "Elemento 27"), ItemsModel(28, "Elemento 28"), ItemsModel(29, "Elemento 29"), ItemsModel(30, "Elemento 30"),
ItemsModel(31, "Elemento 31"), ItemsModel(32, "Elemento 32"), ItemsModel(33, "Elemento 33"), ItemsModel(34, "Elemento 34"), ItemsModel(35, "Elemento 35"),
ItemsModel(36, "Elemento 36"), ItemsModel(37, "Elemento 37"), ItemsModel(38, "Elemento 38"), ItemsModel(39, "Elemento 39"), ItemsModel(40, "Elemento 40"),
ItemsModel(41, "Elemento 41"), ItemsModel(42, "Elemento 42"), ItemsModel(43, "Elemento 43"), ItemsModel(44, "Elemento 44"), ItemsModel(45, "Elemento 45"),
ItemsModel(46, "Elemento 46"), ItemsModel(47, "Elemento 47"), ItemsModel(48, "Elemento 48"), ItemsModel(49, "Elemento 49"), ItemsModel(50, "Elemento 50")
)
}
itemList.addAll(result)
}
}
```
Estamos usando un init como constructor inicializador que llame a fetchData en cuanto creemos la clase.
En el mainActivity vamos a crear un nuevo composable para usar este nuevo simulacro.
```
@Composable
fun ItemsView(viewModel: ItemsViewModel){
val itemList= viewModel.itemList
LaunchedEffect(Unit){
viewModel.fetchData()
}
Column {
if (viewModel.isLoading){
CircularProgressIndicator()
}else {
LazyColumn{
items(itemList){
item ->
Text(text = item.name)
}
}
}
}
}
```
Y en el mainActivty debemos cambiar el viewModel usado por ItemsViewModel y llamamos a ItemsView para ver cómo queda.
Como ves en lugar de usar un botón se ha lanzado directamente la búsqueda, esto se consigue o bien usando un constructor init en el ItemsViewModel o usando el LaunchedEffect, lee más sobre ambos:
https://kotlinlang.org/docs/classes.html#constructors
https://developer.android.com/jetpack/compose/side-effects?hl=es-419