[Kotlin] Coroutines - ViewModelScope
๋ณธ ๊ฒ์๊ธ์ Coroutine ๊ฐ๋
์ Android ๋ด์์ ์ฌ์ฉ๋๋ ๊ฒ์ ์ ์ ๋ก ์์ฑ๋์๋ค.
#1 ViewModel ์ ์ ํต์ ์ธ ๋ฐฉ์์ Coroutines
import androidx.lifecycle.ViewModel
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
class SampleViewModel : ViewModel() {
private val myJob = Job()
private val myScope = CoroutineScope(Dispatchers.IO + myJob)
fun sampleFunction() {
myScope.launch {
// ์๋ฌด ์ฝ๋
}
}
override fun onCleared() {
super.onCleared()
myJob.cancel()
}
}
์๋ ViewModel์์ Coroutine์ ์ฌ์ฉํ๋ ์ฝ๋๋ค. ViewModel์ด ์ข
๋ฃ๋์์์๋, ViewModel์์ ์์ฑ๋ Coroutine์ ๊ณ์ ์คํ๋ ์ฌ์ง๊ฐ ์๋ค. ๋ฐ๋ผ์, onCleared() ์ฝ๋ฐฑ ํจ์๋ฅผ Overrideํด์ Coroutine์ ์์ ํ๊ฒ ์ข
๋ฃ์์ผฐ๋ค.
ํ์ง๋ง, ์ด ์ฝ๋๋ ์์ฉ๊ตฌ ์ฝ๋(Boilerplate code)์ ์ ํ์ด๋ค. Job ํ๋กํผํฐ์ onCleared() ํจ์์ ์กด์ฌ๋ Project์ ํฌ๊ธฐ๊ฐ ์์ ๋ ๋ชฐ๋ผ๋ ์ปค์ง๋ฉด ์ปค์ง์๋ก, ViewModel์ ๊ฐฏ์๋ ๋ง์์ง๋ฉด์ ๊ณจ์นซ๋ฉ์ด๋ฆฌ๊ฐ ๋๋ค.
#2 lifecycle-viewmodel-ktx ๋ผ์ด๋ธ๋ฌ๋ฆฌ
#2-1 ๊ฐ์
์๋ช ์ฃผ๊ธฐ ์ธ์ ๊ตฌ์ฑ์์๋ก Kotlin ์ฝ๋ฃจํด ์ฌ์ฉ | Android ๊ฐ๋ฐ์ | Android Developers
์ด ํ์ด์ง๋ Cloud Translation API๋ฅผ ํตํด ๋ฒ์ญ๋์์ต๋๋ค. ์๋ช ์ฃผ๊ธฐ ์ธ์ ๊ตฌ์ฑ์์๋ก Kotlin ์ฝ๋ฃจํด ์ฌ์ฉ ์ปฌ๋ ์ ์ ์ฌ์ฉํด ์ ๋ฆฌํ๊ธฐ ๋ด ํ๊ฒฝ์ค์ ์ ๊ธฐ์ค์ผ๋ก ์ฝํ ์ธ ๋ฅผ ์ ์ฅํ๊ณ ๋ถ๋ฅํ์ธ์. Kotlin ์ฝ
developer.android.com
๋คํํ, #1์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์๋ค. ๋ฐ๋ก, lifecycle-viewmodel-ktx๋ค. ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ ViewModelScope๋ฅผ ์ด์ฉํด์ #1 ์ ์์ฉ๊ตฌ ์ฝ๋์ ๋์์ ์์์ ์ผ๋ก ์ํํ ์ ์๋ค. ์ฆ, ํด๋น ์์ฉ๊ตฌ ์ฝ๋๋ฅผ ์ ๊ฑฐํด๋ ๋ฌด๋ฐฉํ๊ฒ ๋ง๋ค ์ ์๋ค.
#2-1 androidx.lifecycle.ViewModel.kt ์ดํด๋ณด๊ธฐ (ViewModelScope์ viewModelScope)
/*
* Copyright 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.lifecycle
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import java.io.Closeable
import kotlin.coroutines.CoroutineContext
private const val JOB_KEY = "androidx.lifecycle.ViewModelCoroutineScope.JOB_KEY"
/**
* [CoroutineScope] tied to this [ViewModel].
* This scope will be canceled when ViewModel will be cleared, i.e [ViewModel.onCleared] is called
*
* This scope is bound to
* [Dispatchers.Main.immediate][kotlinx.coroutines.MainCoroutineDispatcher.immediate]
*/
public val ViewModel.viewModelScope: CoroutineScope
get() {
val scope: CoroutineScope? = this.getTag(JOB_KEY)
if (scope != null) {
return scope
}
return setTagIfAbsent(
JOB_KEY,
CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
)
}
internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope {
override val coroutineContext: CoroutineContext = context
override fun close() {
coroutineContext.cancel()
}
}
ViewModelScope๋ ViewModel์ ์๋ช
์ฃผ๊ธฐ๋ฅผ ์ฐธ์กฐํด, ViewModel์ด ์๋ฉธ๋ ๋ ์์์ ์ข
๋ฃ๋๋ CoroutineScope๋ค. #3-1์์์ฒ๋ผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ถ๋ฌ์จ ์๊ฐ๋ถํฐ ViewModelScope๋ ViewModel์ ํ๋กํผํฐ๋ก์ ์๋ ์์ฑ๋๋ค. ํด๋น ํ๋กํผํฐ์ ์ด๋ฆ์ ์ฒซ ๊ธ์๊ฐ ์๋ฌธ์์ธ, viewModelScope๋ค. viewModelScope๋ coroutineScope์ ๋น์ทํ๊ฒ ์ฌ์ฉํ๋ฉด ๋๋ค.
#3 ViewModelScope ์ฌ์ฉํ๊ธฐ
#3-1 build.gradle.kts (Module)์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ค์ด๋ก๋
plugins {
...
}
android {
...
}
dependencies {
...
// ViewModelScope
val lifecycle_version = "2.6.2"
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version")
...
}
์ฌ๊ธฐ์ ์๋ ๊ตฌ๋ฌธ์ ๋ณต์ฌํ์ฌ ๋ชจ๋ ์์ค build.gradle์ ๋ถ์ฌ๋ฃ๋๋ค. ์ด์ ๋ถํฐ ViewModelScope(viewModelScope)๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
#3-2 ViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
class sampleViewModel : ViewModel() {
fun sampleFunction() {
viewModelScope.launch {
// ์๋ฌด ์ฝ๋
}
}
}
#1์ ์ฝ๋๋ฅผ ์์ ํ๋ค.
#4 ์์ฝ
ViewModel์์์ CoroutineScope ์์ฑ ๋ฐ Cancellation์ ์์ํํ๋ค.