Diferencia entre CoroutineScope y coroutineScope en Kotlin

David Mbochi Njonge 15 febrero 2024
  1. Crear un nuevo proyecto de Kotlin
  2. Crear un botón en el diseño principal
  3. Usa CoroutineScope en Kotlin
  4. Usar coroutineScope en Kotlin
  5. Conclusión
Diferencia entre CoroutineScope y coroutineScope en Kotlin

La documentación de Kotlin define coroutine como una ejecución que se puede suspender mientras espera que se ejecuten algunas tareas en segundo plano, como descargar un recurso de una red.

Coroutine nos ayuda a lograr la concurrencia ya que otros cálculos continúan ejecutándose cuando se suspende una corrutina. Tenga en cuenta que las corrutinas son independientes del subproceso que están utilizando porque no se garantiza que reanudarán la ejecución en el subproceso que estaban utilizando.

Para crear una nueva rutina, debemos hacerlo dentro de un ámbito. En este tutorial, aprenderemos cómo el alcance en la concurrencia no estructurada afecta las rutinas secundarias y cómo resolver el problema del alcance usando la concurrencia estructurada.

Crear un nuevo proyecto de Kotlin

Este tutorial utilizará IntelliJ IDEA, pero puede usar cualquier entorno de desarrollo preferido.

Abra IntelliJ IDEA y seleccione Archivo > Nuevo > Proyecto. En la ventana que se abre, seleccione Android en la parte inferior izquierda, luego seleccione Actividad vacía en el lado derecho, como se muestra a continuación.

Proyecto Android - Actividad vacía

Presione el botón Siguiente y en la ventana que se abre, ingrese el nombre del proyecto como CoroutineScope, ingrese el nombre del paquete como com.coffeedev.coroutinescope, seleccione Kotlin en la sección Idioma y seleccione API 19 en la sección SDK mínimo.

Asegúrese de que estos detalles sean como se muestra a continuación.

detalles del proyecto

Presione el botón con la etiqueta Crear para generar un nuevo proyecto de Android. Esta acción crea una nueva aplicación que contiene una actividad llamada MainActivity y un diseño llamado actividad_principal.

Usaremos estos archivos para probar los ejemplos que cubrimos en este tutorial. Asegúrese de tener una conexión a Internet activa para agregar las dependencias requeridas a nuestra aplicación.

Para trabajar con coroutines, necesitamos agregar la dependencia kotlinx-coroutines-core a nuestro proyecto. Copie y pegue la siguiente dependencia en el archivo build.gradle para agregar la dependencia coroutine.

dependencies {
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
}

Crear un botón en el diseño principal

Abra el archivo de diseño acivity_main.xml en src/main/res/layout y copie y pegue el siguiente código en el archivo.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:gravity="center_horizontal"
        tools:context=".MainActivity" >

    <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="100dp"
            android:text="@string/button_text"/>

</LinearLayout>

Este código crea un LinearLayout que contiene solo una Vista de tipo Botón. Usaremos este botón para invocar las rutinas en nuestra aplicación.

Asegúrese de que el diseño final sea como se muestra a continuación.

Diseño de la aplicación

El botón se etiqueta usando un recurso de cadena como lo indica el atributo texto. Copie y pegue el siguiente recurso de cadena en el archivo llamado strings.xml ubicado en la carpeta src/main/res/values.

Esto crea un texto para nuestro botón, y se accede a este texto usando el nombre button_text.

<resources>
    <string name="app_name">CoroutineScope</string>
    <string name="button_text">Press Me</string>
</resources>

Usa CoroutineScope en Kotlin

En la sección de introducción, mencionamos que para crear una nueva rutina, debemos hacerlo dentro de un ámbito. Aquí es donde entra en juego el CoroutineScope.

Para ver esto en acción, copie y pegue el siguiente código en el archivo MainActivity.kt en la carpeta src/main/java/com/coffeedev/coroutinescope.

package com.coffeedev.coroutinescope

import android.os.Bundle
import android.widget.Button
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val button = findViewById<Button>(R.id.button)

        button.setOnClickListener {
            CoroutineScope(Dispatchers.Main).launch {
                val message = getLoopProduct();
                Toast.makeText(applicationContext, "Message: $message", Toast.LENGTH_LONG)
                    .show();
            }
        }

    }

    private suspend fun getLoopProduct(): Int {
        var value = 1;
        CoroutineScope(Dispatchers.IO).launch {
            for (number in 1..5) {
                delay(15);
                value *= number;
            }
        }
        return value;
    }

}

En este código, hemos creado una función de suspensión llamada getLoopProduct() que devuelve el producto de un bucle for. El bucle for se ejecuta mediante una rutina que se ejecuta mediante los subprocesos Dispatchers.IO, pasados como argumento de CoroutineScope().

Para cada iteración del bucle for, hay un retraso de 15 milisegundos, lo que suspende el hilo que se está ejecutando actualmente.

En el método de ciclo de vida onCreate(), hemos creado un nuevo ámbito que se ejecuta utilizando el subproceso Dispatchers.Main, que es simplemente el subproceso principal. Tenga en cuenta que la corrutina de getLoopProduct() es un elemento secundario de la corrutina creada dentro del método onCreate() porque la función suspender se invoca dentro de él.

Las corrutinas creadas a partir de diferentes ámbitos se ejecutan de forma independiente. Dado que la corrutina secundaria usa un alcance diferente al de la corrutina principal, la principal no espera a que la secundaria termine de ejecutarse.

Este tipo de ejecución se conoce como Concurrencia no estructurada.

La corrutina en nuestro método onCreate() se ejecuta solo una vez y termina. Esto significa que la rutina secundaria continúa ejecutándose en segundo plano y puede exponer nuestra aplicación a pérdidas de memoria.

Usamos el botón creado en nuestro diseño para mostrar un Toast que contiene el valor devuelto por getLoopProduct(). El método setOnClickListener() muestra el Toast en pantalla cuando pulsamos el botón.

Ejecute este código y observe que Toast muestra un valor de 1 ya que la rutina principal se suspendió antes de que la rutina secundaria terminara de ejecutarse.

Producción:

Concurrencia no estructurada

Usar coroutineScope en Kotlin

La diferencia entre CoroutineScope() y coroutineScope() es que este último crea un nuevo ámbito sin crear una nueva corrutina. La corrutina secundaria utiliza el coroutinoscopio principal, lo que garantiza que se complete antes de que la corrutina principal complete la ejecución.

Este tipo de ejecución se conoce como concurrencia estructurada.

Para ver esto en acción, reemplace la función suspender en el ejemplo anterior con la que se proporciona a continuación.

   private suspend fun getLoopProduct(): Int {
        var value = 1;
        coroutineScope {
            for (number in 1..5) {
                delay(15);
                value *= number;
            }
        }
        return value;
    }

Dado que el código en el método onCreate() no cambia, la rutina secundaria usa el ámbito principal, que se ejecuta en el subproceso principal para ejecutar el bucle for. La rutina principal espera a que la rutina secundaria ejecute el bucle for antes de que finalice.

Ejecute este código y observe que el Toast muestra un valor de 1 20. Dos indica que la corrutina secundaria está ejecutando todo el ciclo sin terminación debido a la reutilización del ámbito principal.

Producción:

Concurrencia estructurada

Conclusión

En este tutorial, hemos aprendido cómo el alcance de la concurrencia no estructurada afecta las corrutinas secundarias y cómo resolver el problema usando la concurrencia estructurada. Los temas principales que hemos cubierto son cómo usar CoroutineScope() para crear ámbitos independientes y cómo usar coroutineScope() para reutilizar el ámbito principal.

David Mbochi Njonge avatar David Mbochi Njonge avatar

David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.

LinkedIn GitHub

Artículo relacionado - Kotlin Coroutine