저번 글에서 CoroutineScope에 대해서 자세히 알아보았다면, 이제는 실전으로 안드로이드에서 제공하는 ViewModelScope와 lifecycleScope에 대해서 알아보자. ViewModelScope와 lifecycleScope는 코루틴의 생명주기를 효율적으로 관리할 수 있도록 도와주고, 각각 ViewModel과 LifecycleOwner에 연관된 코루틴 범위를 제공하고, 이를 통해 안드로이드 앱에서의 메모리 누수를 방지할 수 있다.
ViewModelScope
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]
ViewModelScope는 ViewModel을 대상으로 정의된다. 이 스코프에서 시작된 모든 코루틴은 ViewModel이 삭제되면 자동으로 취소된다. 코루틴은 ViewModel이 활성 상태인 경우에만 실행해야 할 작업이 있을 때 유용하다.
- ViewModel.onCleared이 호출되면 취소된다
- Dispatchers.Main.Immediate이 기본 컨텍스트이다
아래는 ViewModelScope의 내부코드이다
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()
}
}
LifecycleScope
CoroutineScope tied to this LifecycleOwner's Lifecycle.
This scope will be cancelled when the Lifecycle is destroyed. This scope is bound to Dispatchers. Main. immediate.
LifecycleScope는 LifecycleOwner의 생명주기와 함께하는 코루틴 범위를 제공한다. 이는 Activity나 Fragment와 같은 컴포넌트의 생명주기를 따르고, lifecycleScope 내에서 시작된 코루틴은 해당 컴포넌트가 활성 상태일 때만 실행되며, 컴포넌트가 파괴되면 자동으로 취소된다. 예를 들어, UI 업데이트와 관련된 비동기 작업을 lifecycleScope 내에서 실행할 수 있고 , 이를 통해 Activity나 Fragment가 더 이상 활성 상태가 아닐 때 불필요한 리소스 사용을 방지할 수 있다.
- onDestroy()가 호출되면 취소된다
- Dispatchers.Main.Immediate이 기본 컨텍스트이다
viewModelScope와 lifecycleScope를 통해서 개발자들은 코루틴을 따로 해제해줄 필요없이 UI / 뷰모델의 생명주기에 맞춰 코루틴 스코프를 취소할 수 있다. 이를 통해, 메모리 누수를 줄이고 더욱 안전한 사용이 가능하다.
다만, 잠시 액티비티가 보이지 않는 상황 또는 백그라운드로 내리는 상황과 같이 onStop()에 해당하는 생명주기일때는 onDestroy()가 아니므로 여전히 코루틴이 유효하다. 따라서 이와 같은 경우에 백그라운드로 내려간 앱이 계속해서 메모리를 사용하므로 성능에 좋지않고, 메모리 누수의 위험이 증가한다.
그렇다면 onStart() ~ onStop()까지로 코루틴 스코프를 최적화하기 위한 방법은 없을까 ? 물론 생명주기 함수를 오버라이드해 Job을 생성하고 직접 취소해줄 수도 있다. 하지만 그 방법은 너무 번거롭고, 실수로 해제해주지 않을 가능성이 높다. 이를 해결하기 위해 repeatOnLifecycle을 사용하고, 이에 대해 알아보자.
RepeatOnLifecycle
앞서 언급했지만 lifecycle이 특정 상태에 있을 때 코드 블록의 실행을 시작하고 다른 상태에 있을 때 취소하려는 경우가 있을 수 있다. 예를 들어 Lifecycle이 STARTED일 때 흐름을 수집하고 STOPPED일 때 수집을 취소하려고 할 수 있다. 이 방법은 UI가 화면에 표시될 때만 flow를 처리해 리소스를 절약하고 앱 비정상 종료를 방지할 수 있다. 이를 위해 repeatOnLifecycle API가 제공된다.
Runs the block of code in a coroutine when the lifecycle is at least STARTED. The coroutine will be cancelled when the ON_STOP event happens and will restart executing if the lifecycle receives the ON_START event again
repeatOnLifecycle은 Activity가 포그라운드에 있을 때로 한정지어, 특정 Lifecycle이 Trigger 되었을 때 동작하도록 만드는 블록이다. LifecycleOwner(Activity, Fragment)의 Lifecycle이 최소 onStart가 되었을 때 블록에 있는 메서드들이 수행되며, onStop되었을 때는 코루틴 Job이 취소된다. 즉, 포그라운드에서만 작업되어야 하는 코루틴 블록은 repeatOnLifecycle를 활용해 작업하면 된다.
public suspend fun LifecycleOwner.repeatOnLifecycle(
state: Lifecycle.State,
block: suspend CoroutineScope.() -> Unit
): Unit = lifecycle.repeatOnLifecycle(state, block)
이렇게 직접 CoroutineScope를 만들고 취소하지 않고, 안드로이드 앱을 개발할 때 viewmodel, ui 의 생명주기에 맞춰 코루틴 스코프를 취소해 메모리 누수를 막는 좋은 도구들이 있고, 이와 더불어 repeatOnLifecycle에 대해서 알아보았다. 이러한 코루틴 스코프는 안드로이드 앱 개발에서 flow와 함께 쓰여 생산성을 더욱 높이니까 함께 잘 알아두자.
참고자료
수명 주기 인식 구성요소로 Kotlin 코루틴 사용 | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. 수명 주기 인식 구성요소로 Kotlin 코루틴 사용 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Kotlin 코
developer.android.com
'안드로이드 > 꺼진개념다시보기' 카테고리의 다른 글
[Android] 안드로이드 UI 어디까지 아는데 ? - (2) 이미지 형식 : bitmap, vector, SVG, PNG (0) | 2024.08.25 |
---|---|
[Android] 안드로이드 UI 어디까지 아는데 ? - (1) dp, 해상도와 DIP & 픽셀 단위의 이해 (0) | 2024.08.24 |
[Android] Serializable, Parcelable (0) | 2024.07.07 |
[Android] 안드로이드의 UI 상태 저장, onSaveInstanceState (0) | 2024.07.07 |
[Android] Runnable을 UI Thread위에서 실행시키는 법 - view.post, asyncTask, runOnUiThread, handler.post (1) | 2024.06.04 |