본문 바로가기
안드로이드

[안드로이드] repeatOnLifecycle 을 사용하며.

by keel_im 2021. 12. 26.
반응형

안녕하세요 오늘은 repeatOnLifecycle 에 관한 이야기를 써보려고 합니다.

먼저, MVVM 패턴을 사용하면서 LiveData -> Flow 로 변경하고자 하는 이유들이 있었습니다.

ViewModel 에서는 플랫폼에 의존적인 코드를 쓰면 안된다. 이에 LiveData 는 안드로이드 Jetpack 에서 제공해주는 플랫폼 의존적인 컴포넌트이니 이를 변경하기 위해 Flow 를 사용한다거나, 같은 이슈들입니다. 

어떤 것이 더 좋다. 나쁘다가 아니라. 개인에 맞추어서 팀에 맞추어서 조직에 맞추어서 개발을 하면 된다는 것이 결론입니다. (개인적으로 ViewModel 에서 플랫폼 의존적인 코드를 작성하지 않는다는 의미가 저는 모호하고 KMM 같은 클로스 플랫폼을 가지고 오지 않는 이상, 안드로이드에서만 작동하는데. 와 같은 생각들은 있습니다.)

다시 본론으로 돌아와서 안드로이드에서는 repeatOnLifecycle 라는 api 를

"androidx.lifecycle:lifecycle-runtime-ktx:2.4.0-alpha01"

에서부터 지원해주기 시작했습니다. 

https://medium.com/androiddevelopers/repeatonlifecycle-api-design-story-8670d1a7d333

 

repeatOnLifecycle API design story

In this blog post, you’ll learn the design decisions behind the Lifecycle.repeatOnLifecycle API.

medium.com

위 링크에서 자세한 얘기를 확인할 수 있습니다. 

결국 LiveData 와 Flow 에 특성에 관한 이야기 입니다. LiveData 는 UI 컴포넌트에 생명주기를 알고 있지만, Flow 는 Kotlin 에서 지원해주는 도구 이기 때문에, 안드로이드 UI 컴포넌트에 관한 생명주기를 인식하는 방법이 일반적인 코드로는 힘듭니다. 

이에 repeatOnLifecycle 라는 suspend fun 이라는 함수를 도입하여 Flow 에서도 안전하게 UI 를 인식하며 데이터를 가져올 수 있게 함입니다. 

한번 코드를 보고 설명해보겠습니다. 

fun LifecycleOwner.repeatCallDefaultOnStarted(state: Lifecycle.State = Lifecycle.State.STARTED, block: suspend CoroutineScope.() -> Unit){
    lifecycleScope.launch {
        lifecycle.repeatOnLifecycle(state, block)
    }
}

먼저 위와 같은 확장함수를 작성하였습니다. 기본적으로 UI 가 보이는 STARTED 에서 작동할 수있도록 기본적으로 state 를 Lifecycle.State.STARTED 로 잡아두었습니다. 

이렇게 작성하게 되면, 따로 파라미터를 작성하지 않는 경우는 STARTED 에서 Flow 에 데이터를 수집할 수 있고 state 를 따로 설정하는 경우 CREATED 나 DESTROYED 에서도 수집할 수 있습니다. 

예를 들어보겠습니다.

private fun observeFlow() = viewLifecycleOwner.repeatCallDefaultOnStarted {
    viewModel.state.collect {
      when (it) {
        is SearchListState.UnInitialized -> requireActivity().toast("데이터 설정 중입니다.")
        is SearchListState.Loading -> requireContext().toast("데이터 로딩 중")
        is SearchListState.Searching -> {
          handleSuccess(it)
        }
        is SearchListState.Error -> {
          handleError(it)
          viewModel.errorLogging(it.message!!)
        }
      }
    }
 }

위 함수는 검색을 담당하는 SearchFragment 에서 ViewModel 에 검색흐름을 가지고 있는 함수에서 Flow 데이터를 수집하는 모습니다. 

LiveData 를  옵저빙하는 것과 다르지 않습니다. 그저 Flow 를 데이터를 가지고 있는 것 보다는 데이터의 흐름이기 때문에 collect 를 사용한다는 기본적인 인식만 있으면 될 것 같습니다. 

아직 프로젝트에서 Flow 를 사용하면서 이해되는 부분, 이해되지 않는 부분이 많습니다. 사실 처음에는 필요한 이유를 알지 못했지만, 멀티 모듈을 적용하면서 모듈마다 분리하려고 하니 DI 의 필요성이 늘어나고 이에 아키텍처를 고민하니 왜 생겼는지 이제 느끼는 정도 입니다. 말 그대로 필요성입니다. 

Flow 에 관한 고찰이나 아이디어가 생길 경우 보충하도록 하겠습니다. 

감사합니다. 

반응형

댓글