【Android Studio】CoroutineScopeの種類!GlobalScope/viewModelScope/lifecycleScopeの違い
この記事からわかること
- Android StudioのKotlin CoroutinesのCoroutineScopeとは?
- GlobalScope/viewModelScope/lifecycleScopeの違い
index
[open]
\ アプリをリリースしました /
公式リファレンス:Use Kotlin coroutines with lifecycle-aware components
環境
- Android Studio:Meerkat
- Kotlin:2.0.21
CoroutineScopeとは?
interface CoroutineScope
CoroutineScopeは、Androidアプリ開発で非同期処理を実装できる公式ライブラリ「Kotlin Coroutines」に含まれるinterfaceです。Kotlin Coroutinesではコルーチンという単位で非同期処理が定義されています。そのコルーチンを実行するために必要な情報(スレッドの指定やエラーハンドリングなど)はCoroutineContextが保持しています。そしてコンテキストを提供するのがCoroutineScopeです。
CoroutineScopeはコルーチンを実行できる有効範囲(スコープ)を提供します。これは何かに紐づけられることでスコープとして成り立ちます。ここでCoroutineScopeの種類を見てみます。
CoroutineScopeの種類
- GlobalScope:アプリケーション全体のライフサイクルに関連付けられたスコープ。
- ViewModelScope:ViewModel内で使えるスコープ。ViewModelが破棄されるとコルーチンも自動でキャンセル
- LifecycleScope:ActivityやFragment内で使えるスコープ。特定のライフサイクル状態に合わせたコルーチンを実行
- MainScope:UIスレッドで処理を実行したい場合に使えるスコープ。cancelメソッドを明示的に呼び出してキャンセル
- CoroutineScope:自作管理できるスコープ。cancelメソッドを明示的に呼び出してキャンセル
このように基本的には特定のクラスなどの生成〜破棄までのライフサイクルと紐づくことで有効範囲(スコープ)は定義されます。そしてスコープに合わせて管理されているコルーチンの生成や破棄を行なってくれます。これにより不要なコルーチンが残り続けたり、メモリリークなどを起こさないようになっています。
GlobalScope
GlobalScopeはその名前の通りグローバルなCoroutineScopeです。アプリケーション全体のライフサイクルに紐づけられているためアプリが終了しない限り中のコルーチンも自動で破棄されることはありません。アプリケーション全体で使用できるのは気軽で良いですが思わぬ問題を起こすかもしれないため使用するには注意が必要です。
GlobalScopeは特に依存関係を追加することなく基本的にどこでも使用することができます。例えば以下はDataStoreを使用してデータを操作する処理をGlobalScope内で実行しています。テストや簡易的に試してみたい時などに使えて便利です。
val addButton:Button = findViewById(R.id.add_button)
val getButton:Button = findViewById(R.id.get_button)
addButton.setOnClickListener{
GlobalScope.launch (Dispatchers.IO) {
incrementCounter()
}
}
ViewModelScope
ViewModelScopeはJetPackのコンポーネントの1つとして提供されているViewModelに紐づけられているCoroutineScopeです。ViewModel内で定義されたコルーチンはViewModelが破棄されるタイミングで自動的にキャンセルされます。
ViewModelScopeを使えるようにするためには依存関係を追加する必要があります。
dependencies {
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0"
}
追加できたらviewModelScopeでスコープを参照することができます。
class MyViewModel: ViewModel() {
init {
viewModelScope.launch {
// ViewModel がクリアされるとキャンセルされるコルーチン
}
}
}
LifecycleScope
LifecycleScopeはLifecycleオブジェクトに紐づけられているCoroutineScopeです。つまりActivityやFragmentなどのライフサイクルに応じて管理されるようになります。使えるようにするためには依存関係を追加する必要があります。
dependencies {
implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0"
}
追加できたらviewLifecycleOwner.lifecycleScopeでスコープを参照することができます。
class MyFragment: Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewLifecycleOwner.lifecycleScope.launch {
// ライフサイクルに応じて管理されるコルーチン
}
}
}
repeatOnLifecycle
LifecycleScopeではrepeatOnLifecycleを使用することで指定したライフサイクルの時だけコルーチン処理を実行・再開し、状態が下がると一時停止してくれる関数です。
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.state.collect { state ->
// STARTED 以上のときだけcollectされる
updateUI(state)
}
}
}
MainScope
MainScopeはUIスレッドで処理を実行したい場合に使えるスコープです。依存関係の追加なしで使用できます。UIスレッド向けなのでデフォルトでDispatchers.Mainが指定されており、スコープは明示的にcancelメソッドを使用して閉じる必要があります。
class MainActivity : AppCompatActivity() {
private val mainScope = MainScope()
override fun onDestroy() {
mainScope.cancel()
super.onDestroy()
}
}
CoroutineScope
CoroutineScopeは自作できるスコープです。依存関係の追加なしで使用できます。引数にはDispatchers型を指定する必要があり、スコープは明示的にcancelメソッドを使用して閉じる必要があります。
class MainActivity : AppCompatActivity() {
private val myScope = CoroutineScope(Dispatchers.Default)
override fun onDestroy() {
myScope.cancel()
super.onDestroy()
}
}
cancelしたScopeは再利用できない
一度でもcancelメソッドを実行したスコープは再利用することができません。そのためその後にlaunchやasyncで実行しようとしても即時にキャンセルされてしまいます。
// スコープをキャンセル
scope.cancel()
scope.launch {
// これは実行されない
println("Coroutine : start")
}
そのため再利用したい場合は再度スコープを生成する必要があります。またisActiveプロパティからキャンセルされているかどうかを識別することも可能です。
// 再度格納する
myScope = CoroutineScope(Dispatchers.Default)
if (scope.isActive) {
// キャンセルされていない
}
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。







