LiveData with Coroutines and Flow — Part I: Reactive UIs(학습 및 번역)
Part I: Reactive UIs
Android 초창기부터 우리는 Android 수명 주기가 이해하기 어렵고 극단적인 경우로 가득 차 있으며 ,
정상 상태를 유지하는 가장 좋은 방법은 가능한 한 이를 피하는 것이라는 것을 빨리 배웠습니다.
이를 위해 권장된 layered architecture를 사용하여,
수명 주기에 대해 너무 많이 고민하지 않고, UI 독립적인 코드를 작성할 수 있습니다.
예를 들어, 비즈니스 로직(앱이 실제로 하는 일)을 포함하는 domain layer와 data layer를 추가할 수 있습니다.
또한, 우리는 presentation layer가 다른 책임을 가진 다른 구성요소로 분할될 수 있다는 것을 배웠습니다.
View - LifeCycle CallBack, (사용자 이벤트 및 navi을 처리하는 Activity 또는 Fragment)
Presenter / ViewModel - View에 데이터를 제공하고 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 범위를 정의할수 있고, 코드 정리와 같이 많은 상용구를 제거를 알아서 해준다
구조화된 동시성을 "자동 취소"로 생각하십시오.