https://developer.android.com/topic/architecture/ui-layer?hl=ko
생각보다 잘 읽히는 파트여서, 원문만 봐도 충분합니다.
UI Layer 에서는 UiStateHoler(ex. ViewModel) 이 UiState 생성을 책임집니다.
UI elements 는 UiState 를 화면에 그리고, 사용자와 상호작용합니다.
이벤트가 위로 전파해갈 때, 데이터가 아래로 내려올 때,
단방향성을 지향해야, 유지/보수가 수월하고 가독성도 좋습니다.
블로그 포스팅을 보여주는 화면의 경우,
Datasource 에서 title, content 등을 받아서
UI Layer 에서는 이를 UiState 로 변환합니다.
data class PostingUiState {
val title: String,
val content: String,
val favoriteCount: int
}
UI 는 UiState 를 보고 화면에 타이틀과 콘텐츠를 보여주겠죠.
만약, 이 포스팅에 '좋아요' 를 클릭한다면,
뷰에서 발생한 이벤트가 Datasource 까지 올라가게되고(Upstream),
좋아요+1 을 원격에 반영하고, 결과가 다시 내려와서(Downstream)
UiState 를 만들어서 화면에 반영하게 됩니다.
UI 자체가 데이터의 유일한 소스인 경우를 제외하고 UI에서 UI상태를 직접 수정해서는 안 됩니다.
이 블로그 포스팅 화면에 글씨크기 +,- 버튼이 있다고 가정해볼게요.
서비스 스펙상 글씨크기는 디폴트 크기가 기본이고, 키우거나 줄인다고 해도,
이를 원격에서 설정 값으로 관리해주지는 않는다고 해볼게요.
이런 경우에, "디폴트 글씨 크기를 갖는 글씨크기조절 Widget" 이 유일한 소스라고 볼 수 있겠죠.
사용자는 +,-버튼으로 상호작용을 하게 되겠지만, 이 이벤트는 DataSource 까지 올라갈 일이 없습니다.
그렇다고 UiState 에서 글씨크기의 속성을 가변으로 생각하면 안되겠어요.
상호작용에 따라 UI Layer 내에서 글씨크기를 변경해주고 새로운 UiState 를 만들어주는 것이 좋겠습니다.
ViewModel 즉, 상태 홀더가 UiState 를 책임지고 만들어 주면,
UI 는 이 UiState 를 책임지고 그려줘야해요.
보통, LiveData 또는 StateFlow 처럼 관찰 가능한 데이터 홀더가 이 다리 역할을 합니다.
UI 에서 '관찰 가능한' 데이터 홀더를 사용하기 때문에, ViewModel 이 직접 UI 에 Rendering 을 지시하지 않아도 됩니다. 즉, ViewModel 은 UI elements 에 의존성을 갖지 않고 단순히 UiState 를 만드는 일에만 집중할 수 있어요.
MVP 에서 MVVM 패턴으로 넘어가는 이유도 바로 여기에 있죠.
ViewModel 에서 변경 불가능한 스트림을 노출하여, 이를 구독하는 UI elements 에서 UiState 를 변경할 수 없도록 제한하는 것도 자주 사용되는 방법입니다.
TBD
TBD
TBD
TBD