Lifecycles helping Kotlin Coroutines

Android에서 제공하는 모든 LifecycleOwner를 정리해봅니다.

Sungyong An
7 min readSep 7, 2020

ViewTreeLifecycleOwner에 대한 내용이 누락되어 추가했습니다. 🙇

요즘에는 Android 비동기 처리에 Kotlin Coroutines 사용을 좀 더 선호한다고 생각합니다. Kotlin이 기본 언어로 좀 더 익숙해지기도 했고, AndroidX에서 제공하는 대부분의 Component가 Coroutines을 지원하고 있습니다. 심지어 최근에는 Kotlin 만으로 작성된 컴포넌트들이 속속 추가되고 있기도 합니다. 🤔

오늘은 이런 Android 개발환경의 변화 속에서 Kotlin Coroutines을 좀 더 손쉽게 사용할 수 없을지 간단히 살펴보려고 합니다.

시작하기 전에

Android에서 어떤 작업이 오랜 시간 Main Thread를 점유하고 있으면, 사용자는 화면이 멈춘 것처럼 느끼게 되는데요. 이런 경우에는 비동기 처리를 통해, 사용자에게 더 나은 UX를 제공할 수 있습니다. 주로 DB나 API를 연동할 때는 비동기 처리가 필수겠죠.

아래는 간단한 Coroutines 코드로, CoroutineScope 내에서 호출하면 됩니다. 이미 많은 분들이 사용하고 계실 것 같습니다.

suspend fun doSomething(): String {
... long-running task ...
}

다만 Android에는 Lifecycle이 있어서, 앱 종료 / 화면 전환 등으로 더이상 결과가 필요하지 않게 되면 호출을 멈춰줘야 합니다. 물론 직접 Lifecycle에 따라 CoroutineScope를 잘 관리해주면 됩니다만, 이왕이면 Android Platform에서 직접 제공하는 라이브러리를 사용하는 것이 안정성이나 유지보수 측면에서 더 좋겠죠.

AndroidX Lifecycle

네, 이걸 얘기하려고 서론이 길었습니다. 🤣

Lifecycle은 Android Platform에서 직접 제공하는 라이브러리로, KTX에서는 다양한 컴포넌트들의 Lifecycle과 연동되는 CoroutineScope를 제공합니다.

ViewModelScope

먼저 ViewModel에서 사용할 수 있는 CoroutineScope입니다.
사용하려면 아래처럼 KTX 라이브러리를 설치해야 합니다.

implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$version"

사용하는 코드는 간단합니다. onCleared()가 호출되면 중지됩니다.

class MyViewModel : ViewModel() {  fun method() {
viewModelScope.launch {
doSomething()
}
}
}

LifecycleScope

ViewModel을 사용하지 않는다면, LifecycleScope를 고려해볼 수 있습니다. Activity, Fragment 같은 LifecycleOwner 구현체에서 사용할 수 있습니다.
사용하려면 아래처럼 KTX 라이브러리를 설치해야 합니다.

implementation "androidx.lifecycle:lifecycle-runtime-ktx:$version"

사용하는 코드는 간단합니다. DESTROYED 상태가 되면 중지됩니다.

class MyActivity : AppCompatActivity() {  private fun method() {
lifecycleScope.launch {
doSomething()
}
}
}

⚠️ 주의해야 할 점은 Fragment는 2개의 Lifecycle이 있으므로 LifecycleOwner를 잘 선택해줘야 합니다. 대부분의 경우에는 viewLifecycleOwner를 사용하는 것을 권장드립니다.

class MyFragment : Fragment() {  private fun method() {
viewLifecycleOwner.lifecycleScope.launch {
doSomething()
}
}
}

LifecycleService

간혹 Background 작업이 필요한 경우도 있는데요. WorkManager를 사용하는 경우에는 CoroutineWorker를 지원하므로 손쉽게 사용할 수 있겠지만, Service는 Platform API라서 CoroutineScope를 직접 관리해야만 할 것 같습니다.

다행히도 AndroidX Lifecycle에서는 Service도 지원하고 있습니다. 👏 LifecycleService는 LifecycleOwner를 구현한 Service 확장 클래스입니다.
사용하려면 아래처럼 확장 라이브러리를 추가로 설치해야 합니다.

implementation "androidx.lifecycle:lifecycle-service:$version"

사용하는 코드는 간단합니다. 기존에 사용하던 Service를 LifecycleService로 변경한 후, lifecycleScope를 사용하면 됩니다.

class MyService : LifecycleService() {  private fun method() {
lifecycleScope.launch {
doSomething()
}
}
}

ProcessLifecycleOwner

더 나아가 Application 전역으로 처리하고 싶은 경우도 있을 수 있는데요. Kotlin에서 제공하는 GlobalScope를 사용해야 하나, 아니면 항상 WorkManager와 같은 대체 API를 이용해야 하나 고민이 됩니다.

이런 경우에 사용할 수 있는 LifecycleOwner가 제공됩니다.
사용하려면 확장 라이브러리를 추가로 설치해야 합니다.

implementation "androidx.lifecycle:lifecycle-process:$version"

사용하는 코드는 간단합니다.

ProcessLifecycleOwner.get().lifecycleScope.launch {
doSomething()
}

ViewTreeLifecycleOwner (alpha)

마지막으로 View에서도 LifecycleOwner가 제공됩니다.
사용하려면 라이브러리 버전을 올려야 합니다. (아직은 alpha입니다. 😆)

implementation "androidx.lifecycle:lifecycle-runtime:2.3.0-alpha07"

사용하는 코드는 역시나 간단한데요. 정확하게는 View의 Lifecycle이 아닌, View가 붙어있는 Activity/Fragment의 Lifecycle을 가져옵니다. 따라서 View가 attach되지 않은 경우에는 null이 반환될 수 있습니다.

ViewTreeLifecycleOwner.get(view)?.lifecycleScope?.launch {
doSomething()
}
// Using KTX
view.findViewTreeLifecycleOwner()?.lifecycleScope?.launch {
doSomething()
}

정리

사용처에 따른 API를 매치하고 마무리하겠습니다.

  • Activity, Fragment — lifecycleScope
  • View (in ⍺)— ViewTreeLifecycleOwner + lifecycleScope
  • ViewModel — viewModelScope
  • Service — LifecycleService + lifecycleScope
  • Application — ProcessLifecycleOwner + lifecycleScope

참 쉽죠? 🖼 👨‍🎨

오늘은 Android에서 제공하는 CoroutineScope, LifecycleOwner를 간단히 살펴봤는데요. 역시 ‘Android는 다 계획이 있구나’라는 생각이듭니다. Android에서 Coroutines을 사용하는데 작게나마 도움이 되었으면 좋겠습니다. 🙏

--

--