Diferencia entre CoroutineScope y coroutineScope en Kotlin
- Crear un nuevo proyecto de Kotlin
- Crear un botón en el diseño principal
-
Usa
CoroutineScope
en Kotlin -
Usar
coroutineScope
en Kotlin - Conclusión
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.
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.
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.
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:
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:
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 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