Kotlin Coroutines 101 — Jobs
Tags: android, coroutine, programación, kotlin
Published: 2020-05-17 18:57:31

---
title: Kotlin Coroutines 101 — Jobs
published: true
date: 2020-05-17 18:33:01 UTC
tags: android,coroutine,programación,kotlin
canonical_url: https://medium.com/kotlin-dev-reactor/kotlin-coroutines-101-jobs-c4dea9e8200b
---

### Kotlin Coroutines 101 — Jobs

En este artículo estaré vamos a mencionar algunos aspectos que encuentro interesantes sobre los Jobs.

#### ¿Qué es un Job?

En el primer artículo que escribí tuvimos ocasión de lanzar una corutina mediante la acción de un botón. Pero ¿qué pasa si por algún motivo queremos verificar el estado de la corutina o cancelarla, si fuera necesario?. Es aquí donde entra a tallar la tarea de un _Job_.

Un _Job_ es una representación de una corutina y nos va a permitir realizar algunas acciones sobre ella.

#### ¿Cuáles son sus estados?

Los _Jobs_ cuentan con estados, los cuales listaré a continuación:

![](https://cdn-images-1.medium.com/max/1024/1*-s7IzZDbFfZGAdf2NtD1CQ.png)<figcaption>Ciclo de vida de un <em>Job</em></figcaption>

- **New** : representa el estado de creación de una corutina y la asociación de un _Job_ a ella.
- **Active** : este estado representa el momento en el que se inicia ejecución y mantiene la ejecución de una corutina.
- **Completing** : este estado representa el momento en que la corutina ha finalizado su ejecución y precisa esperar a que otras corutinas asociadas a ella o en una relación de padre-hijo finalicen.
- **Completed** : este estado representa el estado final de una corutina, el momento en el que toda su ejecución, incluyendo las corutinas hijas, ha finalizado.
- **Cancelling** : este estado representa el momento en el que se ha cancelado la corutina y se espera la cancelación de los _Jobs_ asociados a ella.
- **Cancelled** : este es el estado final una vez que se ha procedido a la cancelación total o completa.

Debido a la existencia de estos estados, es posible mediante un _Job_ acceder a las siguientes propiedades:

- **isActive** : esta propiedad nos permitirá saber si un _Job_ se encuentra en estado activo o no.
- **isCancelled** : esta propiedad nos permitirá saber si un _Job_ ha sido cancelado o no.
- **isCompleted** : esta propiedad nos permitirá saber si un _Job_ ha finalizado o ha completado todas sus operaciones.

¿Cuándo emplear estas propiedades? La respuesta sencilla sería emplearlas en momentos en los que la ejecución o lógica de tu corutina demande saber si debe continuar o no si el estado de la misma cambia.

#### La función invokeOnCompletion

Un aspecto interesante de los _Jobs_ es que es posible ejecutar código una vez que estos finalizan y esto es gracias a la función invokeOnCompletion(), esta función recibe como parámetro un objeto _nullable_ de tipo Throwable? que nos permitirá validar la causa por la que una corutina fue cancelada.

```
job1.invokeOnCompletion { throwable ->  
    log("Complete my job 1")
    throwable?.let {  
        log("There is a throwable object!")
        when ( it ) {
            is CancellationException -> {
                log( it.message ?: "Without message")
            }
        }
    }  
}  
```

#### ¿Cómo cancelar un job?

Cancelar un _Job_ se puede conseguir mediante la invocación de su función cancel(). Sin embargo, te va a pedir que pases una instancia de la clase CancellationException, preferiblemente hay que agregarle un mensaje que indique la causa por la que se está cancelando el _Job_.

#### ¿Cómo concatenar jobs?

Concatenar _Jobs_ es relativamente sencillo, para ello requerimos ejecutar la función join(). El comportamiento por defecto de la función join() implica que la corutina que lo invoque se suspenda hasta que este _Job_ esté completo. Sin embargo, si al builder de turno le pasamos el parámetro start=CoroutineStart.LAZY lo que acontecerá es que dicho _Job_ pasará a un estado activo en el punto en el que join() sea invocado.

#### ¿Cómo definir una relación de padre/hijo entre Jobs?

Definir una relación de padre e hijos es posible si pasas el _Job_ como parte del contexto de la corutina que quieres definir como _Job_ hijo.

```
val job1 = coroutineScope.launch(start = CoroutineStart.LAZY, 
                                 context = handlerException) {...}

val childCoroutineScope = CoroutineScope(Dispatchers.Main + job1)
val job2 = childCoroutineScope.launch{...}
```

#### ¿Cómo manejar una excepción en un job?

Para manejar excepciones tienes dos forma; la primera, de forma tradicional usando un try/catch en la sección de código que quieres asegurar; la otra, es declarando una instancia de CoroutineExceptionHandler, el cual recibe como parámetros tanto un objeto conteniendo información sobre el contexto de la corutina y un objeto del tipo Throwable. Este objeto debe pasarse como parte del contexto de la corutina.

```
val handlerException = CoroutineExceptionHandler {
    coroutineContext, throwable ->  
        run {  
                log("$coroutineContext - ${throwable.message}")
        }  
}  

val job1 = coroutineScope.launch(context = handlerException ) {...}  

```

Para complementar les dejo un video para complementar el contenido de este artículo, regálenme un Me gusta si les es de utilidad y un comentario en el video.

{% youtube T3cj6NGU4w0 %}

* * *