launch — KotlinのCoroutine Builderで、結果を返さずにコルーチンを開始し、実行を制御するためのJobオブジェクトを返します。このビルダーはfire-and-forgetパターンを実装しています。コルーチンはバックグラウンドスレッドで処理を開始し、自動的に完了します。JetBrainsのドキュメント(2024年)によると、launchはKotlin Coroutinesで並列タスクを実行する主要な方法です。
重要なポイント
launchは、kotlinx.coroutinesのインポートで利用可能なKotlinの拡張関数で、指定されたCoroutineScope内に新しいコルーチンを作成します。通常の関数とは異なり、launch内のコードは並行して実行されます。コルーチンはスレッドをブロックせずに一時停止(suspend)し、後で再開できます。
launchビルダーはKotlinのコルーチンモデルの基本的な構成要素です。計算された値を返しませんが、コルーチンの実行を制御できるJobオブジェクトを返します。別のコルーチン内でlaunchを介して開始されたすべての子コルーチンは、親にバインドされます。
launchビルダーは、CoroutineScope、CoroutineContext、CoroutineStart、およびsuspendブロックの複数のパラメーターを持つインライン関数として定義されています。パラメーターにはデフォルト値があり、launchを一般的なシナリオで便利に使用できます。
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
contextパラメーターは、ディスパッチャー、例外ハンドラー、名前付き要素を組み合わせたCoroutineContextを受け入れます。エラーを分離するために、Dispatchers.IO、Dispatchers.Main、またはSupervisorJobが最も頻繁に渡されます。
Job — コルーチンのライフサイクルを表す返されるオブジェクト。Jobは次の状態を取ることができます:New、Active、Completing、Completed、Cancelling、Cancelled。各状態は実行ステータスを反映し、変更に対応できます。
val job = CoroutineScope(Dispatchers.IO).launch {
repeat(10) { i ->
delay(1000L)
println("進捗: $i")
}
}
println("ジョブはアクティブです: ${job.isActive}")
delay(2500L)
job.cancel()
println("ジョブはキャンセルされました: ${job.isCancelled}")
Jobは階層構造をサポートしています。親コルーチンがキャンセルされると、すべての子コルーチンが自動的にキャンセルされます。SupervisorJobはこの動作を変更します。1つの子コルーチンが失敗しても、他の子コルーチンはキャンセルされません。
構造化された並行処理とは、各コルーチンが特定のCoroutineScope内で開始され、すべての子コルーチンが作業を完了するまでスコープが完了しないことを意味します。launchはこの原則を完全にサポートしています。別のコルーチン内で開始されたコルーチンは、その子コルーチンになります。
ネストされたlaunch呼び出しでは、コルーチンのツリーが形成されます。親コルーチンはすべての子の完了を待機し、予測可能な実行順序を保証し、リソース管理を簡素化します。
fun main() = runBlocking {
launch {
launch {
delay(1000L)
println("子1が完了")
}
launch {
delay(500L)
println("子2が完了")
}
println("すべての子がこの行の前に完了します")
}
}
この動作は、子スレッドが親にバインドされないスレッドベースの並行処理とは異なります。コルーチンでは、すべての子が作業を完了するまで親は完了しません。
launchでの例外処理はJobのタイプに依存します。通常のJobの場合、例外は親コルーチンに伝播し、それをキャンセルします。SupervisorJobまたはSupervisorScopeの場合、例外は分離されます。1つの子コルーチンのエラーは他の子コルーチンに影響しません。
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
try {
riskyOperation()
} catch (e: Exception) {
println("キャッチ: ${e.message}")
}
}
scope.launch {
println("これはSupervisorJobのおかげで引き続き実行されます")
}
キャッチされなかった例外のグローバルな処理には、CoroutineExceptionHandlerが使用されます。これはコルーチン内で処理されなかった例外をキャッチし、アプリケーションをクラッシュさせずにエラーをログに記録できます。
Androidでは、launchはViewModelからWorkManagerまで、あらゆる場所で使用されています。主なパターンは、コンポーネントのライフサイクル終了時にコルーチンを自動キャンセルするために、FragmentでlifecycleScope、ViewModelでviewModelScopeを使用することです。
class ProfileViewModel : ViewModel() {
private val repository = UserRepository()
fun loadProfile(userId: String) {
viewModelScope.launch(Dispatchers.IO) {
val profile = repository.fetchProfile(userId)
withContext(Dispatchers.Main) {
_profileState.update { it.copy(profile = profile) }
}
}
}
}
viewModelScopeは、ViewModelが破棄されると自動的にコルーチンをキャンセルします。これによりメモリリークが排除され、コンテキストを失った後もバックグラウンド操作が継続しないことが保証されます。さらに、withContextを使用してディスパッチャーを切り替えることもできます。
よくある質問
launchはJobを返し、結果を返しません。一方、asyncは結果を取得するためにDeferred<T>を返します。launchはfire-and-forget操作に使用され、asyncは返された値を待機して使用する必要がある場合に使用されます。
保存したJobオブジェクトでjob.cancel()を呼び出します。グループキャンセルの場合は、scope.cancel()でCoroutineScope全体をキャンセルします。コルーチンは協調的である必要があります。isActiveを確認するか、キャンセル可能なsuspend関数を使用します。
launchブロック内でtry-catchを使用するか、CoroutineContextにCoroutineExceptionHandlerを渡します。エラーを分離するにはSupervisorJobを使用すると、1つの子コルーチンの例外が他の子コルーチンをキャンセルしません。
いいえ、launchはCoroutineScopeの拡張関数です。スコープがないと、コルーチンは構造化された並行処理の原則に従うことができません。GlobalScope.launchは注意して使用してください。ライフサイクルにバインドされないコルーチンを作成します。
数はディスパッチャーのスレッドプールによって制限されます。Dispatchers.DefaultはCPUコア数と同じ数のスレッドを使用します。Dispatchers.IOは最大64スレッドをサポートします。より多くのコルーチンが起動されると、キューに入れられます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。