[번역]LiveData에서 Kotlin의Flow로 Migrating

Photo by Jan-Niclas Aberle on Unsplash

DeadData?

LiveData는 여전히 Java 개발자, 초심자 및 간단한 상황을 위한 좋은 솔루션입니다. 하지만 그 외의 나머지는 Kotlin의 Flow로 이동하는 것이 좋은 방법입니다. Flow는 가파른 러닝 커브를 가지고 있지만 Jetbrains에 의해 지원되는 Kotlin 언어의 일부입니다. 그리고 리액티브 모델에 잘 맞는 Compose가 출시되고 있습니다.

Flow: 간단한 것은 어렵고 복잡한 것은 쉽다

LiveData는 데이터를 노출하는 동시에 최신 값을 캐싱하고 Android의 라이프사이클을 이해하는 작업을 수행합니다. 나중에 우리는 그것이 코루틴을 시작하고 나서 복잡한 변형을 발생시킬 수 있다는 것을 알게 되었습니다.

#1: Mutable 데이터 홀더로 one-shot 작업 결과 노출

이것은 코루틴의 결과로 state 홀더를 변경시키는 클래식한 패턴입니다.

  • 이것은 오직 한 가지 값을 가집니다.
  • 이것은 여러 개의 observer를 지원합니다.(flow가 공유됨)
  • 이것은 observer 수에 관계없이 항상 구독하는 것의 최신 값을 받습니다.

#2: one-shot 작업 결과 노출

이것은 이전의 코드와 동일하며, 변경 가능한 backing property없이 코루틴 호출의 결과를 노출시킵니다.

#3: 파라미터가 포함된 one-shot 데이터 로드

사용자의 ID에 따라 달라지는 일부 데이터를 로드하려고 하면 Flow를 노출하는 AuthManager에서 이 정보를 얻을 수 있다고 가정해봅시다.

#4: 매개 변수를 사용하여 데이터 흐름 관찰

이제 이 예시를 사용하여 조금 더 반응적으로 만들어 보겠습니다. 데이터는 가져오진 않지만 관찰되므로 데이터 원본의 변경 내용을 UI에 자동으로 전파합니다.

#5 여러 소스의 결합: MediatorLiveData -> Flow.Combine

MediatorLiveData를 사용하면 하나 이상의 업데이트 소스(관찰 가능한 LiveData)를 관찰하고 새로운 데이터를 가져올 때 어떤 작업을 수행할 수 있습니다. 일반적으로 MediatorLiveData의 값을 업데이트하여 사용합니다.

노출된 StateFlow 구성(stateIn 연산자)

이전에 사용했던 stateIn은 일반적인 flow를 StateFlow로 변환하지만, 구성에 필요한 코드가 요구됩니다. 지금 바로 사용해야하고 자세한 설명이 필요하지 않은 경우 이 조합을 사용하는 것이 좋습니다.

@param scope the coroutine scope in which sharing is started.
@param started the strategy that controls when sharing is started and stopped.
@param initialValue the initial value of the state flow.
This value is also used when the state flow is reset using the [SharingStarted.WhileSubscribed] strategy with the `replayExpirationMillis` parameter.
// scope -> 공유가 시작되는 코루틴 스코프
// started -> 공유가 시작 및 중지 시기를 제어하는 전략을 시작할 수 있는 파라미터
// initialValie -> state flow의 초기 값. 이 값은 [SharingStarted.WhileSubscribed]과 `replayExpirationMillis` 파라미터를 사용하여 state flow가 재설정 되는 경우에도 사용됩니다.
  • Eagerly: 즉시 시작되며 scope가 취소되면 중단됩니다.
  • WhileSubscribed: 이것은 복잡합니다.

WhileSubscribed 전략

WhileSubscribed는 collector가 없을 때 upstream flow를 취소합니다. stateIn을 사용하여 생성된 StateFlow는 데이터를 View에 표시하지만 다른 레이어 또는 애플리케이션(upstream)에서 나오는 flow도 관찰합니다. 이러한 flow를 활성화된 상태로 유지하면 (예를 들어 데이터베이스 연결, 하드웨어 센서 등과 같은 다른 소스에서 데이터를 계속 읽는 경우) 리소스가 낭비될 수 있습니다. 앱이 백그라운드로 전환되면 이러한 코루틴을 중단해야 합니다.

public fun WhileSubscribed(
stopTimeoutMillis: Long = 0,
replayExpirationMillis: Long = Long.MAX_VALUE
)

Stop timeout

문서에 의하면:

  • 최신 값은 여전히 캐시되므로 사용자가 다시 접근할 때 View에 즉시 일부 데이터가 포함됩니다.
  • 구독이 다시 시작되고 새 값이 들어온 후 사용 가능할 때 화면이 새로 리프레시됩니다.

Replay 만료

오래된 데이터가 너무 오랫동안 사라졌을 때 유저에게 오래된 데이터가 표시되지 않도록 하고 로딩 화면을 표시하려면 WhileSubscribed에서 replayExpirationMillis 파라미터를 체크하세요. 이 경우 캐시된 값이 stateIn에 정의된 초기 값으로 복원되므로 매우 편리하고 약간의 메모리도 절약할 수 있습니다. 앱으로 돌아오는 것은 그렇게 빠르지 않겠지만, 오래도니 데이터는 보여주지 않을 것 입니다.

view에서 StateFlow 관찰

지금까지 살펴본 바와 같이, ViewModel의 StateFlow가 더 이상 listening을 하지 않음을 view에게 알려주는 것이 매우 중요합니다. 그러나 lifecycle과 관련된 모든 것이 그렇듯이 그리 간단하지 않습니다. flow를 수집하려면 코루틴이 필요합니다. 그래서 Activity 및 Fragment는 많은 코루틴 빌더를 제공합니다.

  • Fragment.lifecycleScope.launch : 코루틴을 즉시 시작하고 fragment가 파괴되면 취소합니다.
  • Fragment.viewLifecycleOwner.lifecycleScope.launch : 코루틴을 즉시 시작하고 fragment의 viewLifecycle이 파괴되면 취소합니다. UI를 수정하는 경우 viewLifecycle을 사용해야합니다.

LaunchWhenStarted, launchWhenResumed…

특수한 버전의 launch로 불리는 launchWhenXlifecycleOwner가 X 상태가 될 때까지 기다렸다가 lifecycleOwner가 X 상태 아래로 떨어질 때 코루틴을 일시 중단합니다. 주목해야할 것은 lifecycle owner가 파괴될 때까지 코루틴을 취소하지 않는다는 것입니다.

lifecycle.repeatOnLifecycle을사용하여 해결

이 새로운 코루틴 빌더는 우리가 필요로 하는 것을 정확히 수행합니다. 코루틴은 특정 상태에서 코루틴을 시작하고 lifecycle owner가 그 아래 상태로 떨어질 때 코루틴을 중단합니다.

WhileSubscribed(5000)를 통해 StateFlow가 노출되고 repeatOnLifecyle(STARTED)를 통해 수집됨.

요약

ViewModel에서 데이터를 노출하고 View에서 수집하는 가장 좋은 방법은 다음과 같습니다.

  • ✔️️️ repeatOnLifecycle을 사용하여 수집합니다. [예시]
  • Lazily/Eagerly 을 사용하고 repeatOnLifecycle로 수집합니다.

읽어주셔서 감사합니다 🙌

--

--

Android Developer. 3년차 주니어 안드로이드 개발자입니다.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
hongbeom

hongbeom

Android Developer. 3년차 주니어 안드로이드 개발자입니다.