UI 상태
- 화면 UI 상태: 화면에 표시해야 하는 항목입니다. 예를 들어 NewsUiState 클래스에는 UI를 렌더링하는 데 필요한 뉴스 기사와 기타 정보가 포함될 수 있습니다. 이 상태는 앱 데이터를 포함하므로 대개 계층 구조의 다른 레이어에 연결됩니다.
- UI 요소 상태: 렌더링 방식에 영향을 주는 UI 요소에 고유한 속성을 나타냅니다. (Android에서 Scaffold 컴포저블의 ScaffoldState를 예로 들 수 있습니다)
UI 수명 주기와 무관UI 수명 주기에 종속
UI 수명 주기와 무관 | UI 수명 주기에 종속 |
비즈니스 로직 | UI 로직 |
화면 UI 상태 |
UI 상태 생성 파이프라인
- UI 자체에서 생성 및 관리하는 UI 상태
@Composable
fun Counter() {
// The UI state is managed by the UI itself
var count by remember { mutableStateOf(0) }
Row {
Button(onClick = { ++count }) {
Text(text = "Increment")
}
Button(onClick = { --count }) {
Text(text = "Decrement")
}
}
}
- UI 로직 → UI
@Composable
fun ContactsList(contacts: List<Contact>) {
val listState = rememberLazyListState()
val isAtTopOfList by remember {
derivedStateOf {
listState.firstVisibleItemIndex < 3
}
}
// Create the LazyColumn with the lazyListState
...
// Show or hide the button (UI logic) based on the list scroll position
AnimatedVisibility(visible = !isAtTopOfList) {
ScrollToTopButton()
}
}
- 비즈니스 로직 → UI
@Composable
fun UserProfileScreen(viewModel: UserProfileViewModel = hiltViewModel()) {
// Read screen UI state from the business logic state holder
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
// Call on the UserAvatar Composable to display the photo
UserAvatar(picture = uiState.profilePicture)
}
- 비즈니스 로직 → UI 로직 → UI
@Composable
fun ContactsList(viewModel: ContactsViewModel = hiltViewModel()) {
// Read screen UI state from the business logic state holder
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
val contacts = uiState.contacts
val deepLinkedContact = uiState.deepLinkedContact
val listState = rememberLazyListState()
// Create the LazyColumn with the lazyListState
...
// Perform UI logic that depends on information from business logic
if (deepLinkedContact != null && contacts.isNotEmpty()) {
LaunchedEffect(listState, deepLinkedContact, contacts) {
val deepLinkedContactIndex = contacts.indexOf(deepLinkedContact)
if (deepLinkedContactIndex >= 0) {
// Scroll to deep linked item
listState.animateScrollToItem(deepLinkedContactIndex)
}
}
}
}
두 가지 종류의 로직이 모두 UI 상태 생성 파이프라인에 적용되는 경우 비즈니스 로직이 항상 UI 로직보다 먼저 적용되어야 합니다. UI 로직 다음에 비즈니스 로직을 적용하려고 하면 비즈니스 로직이 UI 로직에 종속된다는 것을 의미합니다.
상태 홀더 및 책임
상태 홀더의 책임은 앱이 읽을 수 있도록 상태를 저장하는 것입니다. 로직이 필요한 경우 상태 홀더는 중개자 역할을 하며 필요한 로직을 호스팅하는 데이터 소스에 대한 액세스 권한을 제공합니다. 이러한 방식으로 상태 홀더는 로직을 적절한 데이터 소스에 위임합니다.
- 간단한 UI: UI가 상태를 바인딩합니다.
- 유지관리: 상태 홀더에 정의된 로직을 UI 자체를 변경하지 않고도 반복할 수 있습니다.
- 테스트 가능성: UI 및 상태 생성 로직을 독립적으로 테스트할 수 있습니다.
- 가독성: 코드 리더가 UI 표시 코드와 UI 상태 생성 코드 간의 차이점을 명확하게 알아볼 수 있습니다.
크기나 범위와 관계없이 모든 UI 요소는 상응하는 상태 홀더와 1:1 관계를 갖습니다. 또한 상태 홀더는 UI 상태 변경을 야기할 수 있는 모든 사용자 작업을 수락하고 처리할 수 있어야 하고 후속 상태 변경을 생성해야 합니다.
상태 홀더 유형
- 비즈니스 로직 상태 홀더
- UI 로직 상태 홀더
비즈니스 로직 및 상태 홀더
비즈니스 로직 상태 홀더는 사용자 이벤트를 처리하고 데이터 또는 도메인 레이어에서 화면 UI 상태로 데이터를 변환합니다.
(★ 와닿지 않음..) https://developer.android.com/topic/architecture/ui-layer/stateholders?hl=ko#business-logic
속성 | 세부정보 |
UI 상태 생성 | 비즈니스 로직 상태 홀더는 UI의 UI 상태를 생성해야 합니다. 이 UI 상태는 종종 사용자 이벤트를 처리하고 도메인 및 데이터 레이어에서 데이터를 읽은 결과입니다. |
활동 재생성을 통해 유지됨 | 비즈니스 로직 상태 홀더는 Activity 재생성 전반에 걸쳐 상태 및 상태 처리 파이프라인을 유지하여 원활한 사용자 환경을 제공할 수 있도록 합니다. 상태 홀더를 유지할 수 없어 다시 만드는 경우(일반적으로 프로세스 종료 후) 상태 홀더는 일관된 사용자 환경을 보장하기 위해 마지막 상태를 쉽게 재생성할 수 있어야 합니다. |
장기 지속 상태 보유 | 비즈니스 로직 상태 홀더는 종종 탐색 대상의 상태를 관리하는 데 사용됩니다. 따라서 탐색 그래프에서 삭제될 때까지 탐색 변경 후에도 상태를 유지하는 경우가 많습니다. |
UI에 고유하며 재사용할 수 없음 | 비즈니스 로직 상태 홀더는 일반적으로 특정 앱 기능(예: TaskEditViewModel 또는 TaskListViewModel)의 상태를 생성하므로 이 앱 기능에만 적용됩니다. 동일한 상태 홀더가 다양한 폼 팩터에서 이러한 앱 기능을 지원할 수 있습니다. 예를 들어 모바일, TV, 태블릿 버전의 앱은 동일한 비즈니스 로직 상태 홀더를 재사용할 수 있습니다. |
(데이터 홀더의 생명주기를 알아야 겠다..)
kotlin의 remember: 상태 유지 (Activity 재생성 되도)
@Stable
class NiaAppState(
val navController: NavHostController,
val windowSizeClass: WindowSizeClass
) {
// UI logic
val shouldShowBottomBar: Boolean
get() = windowSizeClass.widthSizeClass == WindowWidthSizeClass.Compact ||
windowSizeClass.heightSizeClass == WindowHeightSizeClass.Compact
// UI logic
val shouldShowNavRail: Boolean
get() = !shouldShowBottomBar
// UI State
val currentDestination: NavDestination?
@Composable get() = navController
.currentBackStackEntryAsState().value?.destination
// UI logic
fun navigate(destination: NiaNavigationDestination, route: String? = null) { /* ... */ }
/* ... */
}
상태 홀더보다 오래 지속되는 종속 항목의 예로는 화면 수준의 상태 홀더에 종속되는 UI 로직 상태 홀더가 있습니다. 이렇게 하면 단기 지속 상태 홀더의 재사용성이 저하되고 실제로 필요한 것보다 더 많은 로직과 상태에 액세스할 수 있습니다.
'아키텍처' 카테고리의 다른 글
[앱 아키텍처] 상태를 호이스팅할 대상 위치 (0) | 2024.01.30 |
---|---|
[앱 아키텍처] 상태 호이스팅 (1) | 2024.01.30 |
[앱 아카텍처] UI 이벤트 (0) | 2024.01.30 |
[앱 아카텍처] UI 레이어 (0) | 2024.01.30 |
[앱 아키텍처] 권장 앱 아키텍처 (0) | 2024.01.30 |