KotlinのCoroutineScopeとcoroutineScopeの違い
- 新しい Kotlin プロジェクトを作成する
- メイン レイアウトにボタンを作成する
-
Kotlin で
CoroutineScope
を使用する -
Kotlin で
coroutineScope
を使用する - まとめ
Kotlin のドキュメントでは、コルーチン を、ネットワークからのリソースのダウンロードなど、一部のバックグラウンド タスクの実行を待機しているときに一時停止できる実行として定義しています。
コルーチンは、コルーチンが中断されたときに他の計算が実行され続けるため、同時実行を実現するのに役立ちます。 コルーチンは使用しているスレッドから独立していることに注意してください。これは、使用していたスレッドで実行が再開されることが保証されていないためです。
新しいコルーチンを作成するには、スコープ内で行う必要があります。 このチュートリアルでは、構造化されていない同時実行のスコープが子コルーチンにどのように影響するか、および構造化された同時実行を使用してスコープの問題を解決する方法を学習します。
新しい Kotlin プロジェクトを作成する
このチュートリアルでは IntelliJ IDEA を使用しますが、任意の開発環境を使用できます。
IntelliJ IDEA を開き、File > New > Project
を選択します。 開いたウィンドウで、以下に示すように、左下のAndroid
を選択し、次に右側の空のアクティビティ
を選択します。
Next
ラベルのボタンを押して、表示されたウィンドウに CoroutineScope
というプロジェクト名、com.coffeedev.coroutinescope
というパッケージ名、言語セクションで Kotlin
を選択し、最小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>
このコードは、Button
タイプの View
を 1つだけ含む LinearLayout
を作成します。 このボタンを使用して、アプリケーションでコルーチンを呼び出します。
最終的なレイアウトが次のようになっていることを確認します。
ボタンは、text
属性で示される文字列リソースを使用してラベル付けされます。 次の文字列リソースをコピーして、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;
}
}
このコードでは、for
ループの結果を返す getLoopProduct()
という名前の suspend
関数を作成しました。 for
ループは、CoroutineScope()
の引数として渡される Dispatchers.IO
スレッドを使用して実行されるコルーチンを使用して実行されます。
for
ループの反復ごとに 15 ミリ秒の遅延が発生し、現在実行中のスレッドが中断されます。
onCreate()
ライフ サイクル メソッドでは、単にメイン スレッドである Dispatchers.Main
スレッドを使用して実行される新しいスコープを作成しました。 getLoopProduct()
のコルーチンは、onCreate()
メソッド内で作成されたコルーチンの子であることに注意してください。これは、suspend
関数が内部で呼び出されるためです。
異なるスコープから作成されたコルーチンは、独立して実行されます。 子コルーチンは親コルーチンとは異なるスコープを使用するため、親は子の実行が完了するまで待機しません。
このタイプの実行は、非構造化同時実行と呼ばれます。
onCreate()
メソッドのコルーチンは 1 回だけ実行され、終了します。 これは、子コルーチンがバックグラウンドで引き続き実行され、アプリケーションがメモリ リークにさらされる可能性があることを意味します。
レイアウトで作成したボタンを使用して、getLoopProduct()
によって返された値を含む Toast
を表示します。 setOnClickListener()
メソッドは、ボタンを押すと画面に Toast
を表示します。
このコードを実行すると、子コルーチンの実行が完了する前に親コルーチンが中断されたため、Toast
の値が 1
と表示されることに注意してください。
出力:
Kotlin で coroutineScope
を使用する
CoroutineScope()
と coroutineScope()
の違いは、後者が新しいコルーチンを作成せずに新しいスコープを作成することです。 子コルーチンは親コルーチンスコープを使用します。これにより、親コルーチンが実行を完了する前に子コルーチンが完了することが保証されます。
このタイプの実行は、構造化同時実行と呼ばれます。
これを実際に見るには、前の例の suspend
関数を以下に示すものに置き換えます。
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
の値を表示することに注意してください。 2 は、親スコープを再利用するために、子コルーチンが終了せずにループ全体を実行していることを示します。
出力:
まとめ
このチュートリアルでは、構造化されていない同時実行の範囲が子コルーチンにどのように影響するか、および構造化された同時実行を使用して問題を解決する方法を学びました。 これまで取り上げてきた主なトピックは、CoroutineScope()
を使用して独立したスコープを作成する方法と、coroutineScope()
を使用して親スコープを再利用する方法です。
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