카테고리 없음

LiveData with Coroutines and Flow — Part I: Reactive UIs(학습 및 번역)

hik14 2022. 11. 8. 15:40

Part I: Reactive UIs

Android 초창기부터 우리는 Android 수명 주기가 이해하기 어렵고 극단적인 경우로 가득 차 있으며 ,

정상 상태를 유지하는 가장 좋은 방법은 가능한 한 이를 피하는 것이라는 것을 빨리 배웠습니다.

 

이를 위해 권장된 layered architecture를 사용하여,

수명 주기에 대해 너무 많이 고민하지 않고, UI 독립적인 코드를 작성할 수 있습니다.

예를 들어, 비즈니스 로직(앱이 실제로 하는 일)을 포함하는 domain layer와 data layer를 추가할 수 있습니다.

또한, 우리는 presentation layer가 다른 책임을 가진 다른 구성요소로 분할될 수 있다는 것을 배웠습니다.

 

View - LifeCycle CallBack, (사용자 이벤트 및 navi을 처리하는 Activity 또는 Fragment)

 

Presenter / ViewModelView에 데이터를 제공하고 View에서 진행 중인 수명 주기 를 알 필요가 없습니다.

즉, View가 다시 생성될 때 no interruptions / clean up 할 필요가 없습니다.

 

ViewModel/Presenter에서 View로 데이터를 보내는 두 가지 메커니즘이 있습니다.

 

- View에 대한 참조를 갖고 직접 호출합니다. 일반적으로 Presenter 작동 방식과 관련이 있습니다.

- Observer에게  Obsevable 데이터를 노출합니다. 일반적으로 ViewModel의 작동 방식과 관련이 있습니다.

 

Android 커뮤니티에서 꽤 잘 확립된 규칙이지만,  가끔 위 두 방법에 동의하지 않는 사람들이 있습니다.

Presenter, ViewModel, MVP 및 MVVM을 다양한 방식으로 정의하는 수백 개의 블로그 게시물이 있습니다

 

내 제안은 presentation layer의 특성에 초점을 맞추고,

Android 아키텍처 구성 요소 ViewModel을 사용하는 것입니다.

 

- 회전, 로케일 변경, 창 크기 조정, 다크 모드 전환 등과 같은 구성 변경을 견뎌냅니다.

- 매우 간단한 수명 주기를 가지고 있습니다. 수명 주기 소유자가 완료되면 호출되는 단일 수명 주기 콜백인 onCleared가 있습니다.

 

ViewModel은 Observer 패턴을 사용하여 사용하도록 설계되었습니다.

 

- View에 대한 참조가 없어야 합니다.

- 관찰자가 무엇인지 알지 못하는 관찰자에게 데이터를 노출합니다. 이를 위해 LiveData를 사용할 수 있습니다.

 

View(Activity, Fragment 또는 Lifecycle 소유자)가 생성되면 ViewModel이 획득되고 View가 구독하는 하나 이상의 LiveData를 통해 데이터 노출을 시작합니다.

구독은 LiveData.observe를 사용하거나 데이터 바인딩 라이브러리를 사용하여 자동으로 설정할 수 있습니다.

 

 

ViewModel의 Activity에 대한 참조가 있는 경우 다음을 확인해야 합니다.

 

 - View가 파괴되면 참조 지우기.

-  View가 transitional state(과도기 상태 즉, Activity/Fragment에서 View만 파괴된 상태).에 있는 경우 액세스를 하면 안된다.

 

그러나 ViewModel+LiveData를 사용하여 더 이상 이를 처리할 필요가 없습니다.

앱 아키텍처 가이드에서 이 접근 방식을 권장하는 이유이다.

 

Scopes

Activity와 fragment는 ViewModel보다 수명이 같거나 짧기 때문에, the scope of operations 에 대해 이야기할 수 있습니다.

operations은 네트워크에서 데이터 가져오기, 결과 필터링 또는 일부 텍스트 배열 계산과 같이 앱에서 수행해야 하는 모든 것입니다.

 

생성하는 모든 operations에 대해 해당 범위, 즉 시작과 취소 사이의 시간 범위를 고려해야 합니다. 두 가지 예를 살펴보겠습니다.

 

- Activity의 onStart에서 operations을 시작하고 onStop에서 중지합니다.

- ViewModel의 init { }에서 operations을 시작하고 onCleared()에서 중지합니다.

 

다이어그램을 보면 각 operation 이 의미 있는 위치를 찾을 수 있습니다.

 

Activity scope가 지정된 operation에서 데이터를 가져오면,  회전 후에 데이터를 다시 가져와야 하므로 대신 ViewModel로 범위를 지정해야 합니다

회전 후 텍스트 컨테이너의 모양이 변경되었을 수 있으므로,  ViewModel 범위의 operation에서 텍스트를 정렬하는 것은 의미가 없습니다.

 

분명히 실제 앱에는 이보다 훨씬 더 많은 범위가 있을 수 있습니다. 

  • Fragment scopes, multiple per screen
  • Fragment ViewModel scopes, one per screen
  • Main Activity scope
  • Main Activity ViewModel scope
  • Application scope

Schedule screen,    Info screen,     MainActivity

 

이렇게 하면 여러가지 다른 범위가 생성될 수 있으므로 모든 범위를 관리하는 것이 부담스러울 수 있습니다.

이 동시성을 구성할 방법이 필요합니다!

 

매우 편리한 솔루션 중 하나는 Kotlin Coroutines입니다.

 

여러 가지 이유로 Android에서 코루틴을 사용하는 것을 좋아합니다

 

- Main Thread에서 벗어나기 쉽습니다.

Android 앱은 부드러운 UX를 위해 스레드 간에 지속적으로 전환하고 있으며 코루틴은 이를 매우 간단하게 만듭니다.

 

- boilerplate Code가 적습니다.

코루틴은  코틀린 패키지의 일부이기 때문에, 일시 중단 기능과 같은 것을 사용하는 것은 아주 쉽습니다.

 

- Structured concurrency

즉, Operation 범위를 정의할수 있고,  코드 정리와 같이 많은 상용구를 제거를 알아서 해준다

구조화된 동시성을 "자동 취소"로 생각하십시오.