Kotlin 中 CoroutineScope 和 coroutineScope 的区别
Kotlin 文档将协程定义为可以暂停的执行,因为它正在等待执行某些后台任务,例如从网络下载资源。
协程帮助我们实现并发,因为当协程挂起时其他计算继续执行。 请注意,协程独立于它们正在使用的线程,因为不能保证它们会在它们正在使用的线程上恢复执行。
要创建一个新的协程,我们必须在一个范围内进行。 在本教程中,我们将学习非结构化并发中的范围如何影响子协程以及如何使用结构化并发解决范围问题。
创建一个新的 Kotlin 项目
本教程将使用 IntelliJ IDEA,但您可以使用任何首选的开发环境。
打开 IntelliJ IDEA 并选择文件 > 新建 > 项目。 在打开的窗口中,选择左下方的Android,然后在右侧选择Empty activity,如下图。
按标有 Next 的按钮,在打开的窗口中,输入项目名称 CoroutineScope,输入包名称 com.coffeedev.coroutinescope,在 Language 部分选择 Kotlin,并在 Minimum SDK 部分选择 API 19。
确保这些详细信息如下所示。
按标有 Create 的按钮生成一个新的 Android 项目。 此操作创建一个新应用程序,其中包含一个名为 MainActivity 的活动和一个名为 activity_main 的布局。
我们将使用这些文件来测试我们在本教程中介绍的示例。 确保您有有效的互联网连接,以便将所需的依赖项添加到我们的应用程序。
要使用协程,我们需要将 kotlinx-coroutines-core 依赖项添加到我们的项目中。 将以下依赖复制并粘贴到 build.gradle 文件中以添加协程依赖。
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
}
在主布局上创建一个按钮
打开 src/main/res/layout 下的 acivity_main.xml 布局文件,将以下代码复制粘贴到文件中。
<?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>
此代码创建一个 LinearLayout,其中仅包含一个 Button 类型的视图。 我们将使用此按钮来调用我们应用程序中的协程。
确保最终布局如下所示。
该按钮使用文本属性指示的字符串资源进行标记。 将以下字符串资源复制并粘贴到 src/main/res/values 文件夹下名为 strings.xml 的文件中。
这为我们的按钮创建了一个文本,并且可以使用名称 button_text 访问该文本。
<resources>
<string name="app_name">CoroutineScope</string>
<string name="button_text">Press Me</string>
</resources>
在 Kotlin 中使用 CoroutineScope
在介绍部分,我们提到要创建一个新的协程,我们必须在一个范围内进行。 这就是 CoroutineScope 的用武之地。
要查看实际效果,请将以下代码复制并粘贴到 src/main/java/com/coffeedev/coroutinescope 文件夹下的 MainActivity.kt 文件中。
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;
}
}
在这段代码中,我们创建了一个名为 getLoopProduct()
的挂起函数,它返回 for 循环的结果。 for 循环使用协程执行,该协程使用 Dispatchers.IO 线程运行,作为 CoroutineScope() 的参数传递。
对于 for 循环的每次迭代,都有 15 毫秒的延迟,挂起当前正在执行的线程。
在 onCreate()
生命周期方法中,我们创建了一个使用 Dispatchers.Main 线程运行的新范围,它只是主线程。 请注意,getLoopProduct()
的协程是在 onCreate()
方法内创建的协程的子级,因为在其中调用了挂起函数。
从不同范围创建的协程独立运行。 由于子协程使用与父协程不同的作用域,因此父协程不会等待子协程完成执行。
这种类型的执行称为非结构化并发。
我们的 onCreate() 方法中的协程只执行一次并终止。 这意味着子协程继续在后台运行,并可能使我们的应用程序面临内存泄漏。
我们使用在布局中创建的按钮来显示包含 getLoopProduct() 返回值的 Toast。 setOnClickListener() 方法在我们按下按钮时在屏幕上显示 Toast。
运行此代码并注意 Toast 显示值 1,因为在子协程完成执行之前父协程已挂起。
输出:
在 Kotlin 中使用 coroutineScope
CoroutineScope()
和 coroutineScope()
之间的区别在于后者创建一个新的作用域而不创建一个新的协程。 子协程使用父协程范围,确保它在父协程完成执行之前完成。
这种类型的执行称为结构化并发。
要查看实际效果,请将上一个示例中的挂起函数替换为下面提供的函数。
private suspend fun getLoopProduct(): Int {
var value = 1;
coroutineScope {
for (number in 1..5) {
delay(15);
value *= number;
}
}
return value;
}
由于 onCreate()
方法中的代码没有变化,子协程使用父作用域,运行在主线程中执行for循环。 父协程在终止之前等待子协程执行 for 循环。
运行这段代码,注意 Toast 显示的值为 1 20。二表示子协程正在执行整个循环,由于重用父作用域而没有终止。
输出:
总结
在本文中,我们了解了非结构化并发的范围如何影响子协程以及如何使用结构化并发解决问题。 我们涵盖的主要主题是如何使用 CoroutineScope()
创建独立作用域以及如何使用 coroutineScope()
重用父作用域。
相关文章
Kotlin 中 Java String[] 的等价物
发布时间:2023/05/13 浏览次数:59 分类:Java
-
本文介绍了 Kotlin 中 Java String[] 的等价物。 我们将看到所有可能的方法来为 Kotlin 实现与 Java 中的 String[] 相同的结果。
将 Java 文件代码转换为 Kotlin
发布时间:2023/05/13 浏览次数:142 分类:Java
-
Kotlin 现在是一种官方的 Android 语言。 因此,您可能希望将 Java 文件更改为 Kotlin。 本文教您如何将 Java 转换为 Kotlin。
在 Kotlin 中使用 forEach
发布时间:2023/05/13 浏览次数:122 分类:Java
-
本文介绍 Kotlin 中 forEach 关键字的概念和使用。 我们将看到一些使用 Kotlin forEach 循环的示例来理解它。
在 Kotlin 中使用 reified 关键字
发布时间:2023/05/13 浏览次数:197 分类:Java
-
reified 关键字是在 Kotlin 中使用泛型时最常使用的编程概念。在本教程中,我们将学习如何使用两种方法解决此问题,包括将类型的类作为泛型函数的参数传递,以及将 reified 关键字与内联函数
Kotlin 中 ! 和 ? 运算符之间的区别
发布时间:2023/05/13 浏览次数:180 分类:Java
-
在 Kotlin 中,断言运算符 !! 和安全调用符 ? 使用 Null 安全。本文介绍空安全的概念。 我们也将通过如何! 和 ? 在 Kotlin 中有助于空安全。
Kotlin 中 is 运算符 与 as 运算符之间的区别
发布时间:2023/05/13 浏览次数:148 分类:Java
-
这篇文章讨论了 Kotlin 中 is 和 as 运算符之间的区别。 我们还将介绍如何以及何时使用每一个。
Android Studio 中的 Kotlin 打印到控制台
发布时间:2023/05/13 浏览次数:52 分类:Java
-
Kotlin 的 logcat 窗口可以实时显示输出,让开发人员能够高效地处理他们的代码。 今天,我们将完成将消息打印到 Kotlin 控制台的步骤。
在 Kotlin 中获取随机数
发布时间:2023/05/13 浏览次数:68 分类:Java
-
随机数是使用一种算法从一组数字中生成的,该算法可确保每个数字的生成概率相等。在Kotlin中使用IntRange的random()扩展函数
在 Kotlin 中使用内联函数
发布时间:2023/05/13 浏览次数:199 分类:Java
-
Kotlin 允许使用内联函数有效地处理更高级的函数。 在本文中,我们将介绍我们需要了解的有关 Kotlin 中的内联函数的所有信息。