[Android Compose] 상태 및 Jetpack Compose / 상태 호이스팅
출처 : https://developer.android.com/jetpack/compose/state?hl=ko#restore-ui-state
상태 및 Jetpack Compose | Android Developers
상태 및 Jetpack Compose 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 앱의 상태는 시간이 지남에 따라 변할 수 있는 값을 의미합니다. 이는 매우 광범위한 정
developer.android.com
이전글에서는 선언형 UI가 무엇인지, 재구성과 부작용이 무엇인지 간단히 살펴보았다.
오늘은 콤포오즈 사용에 있어 빠질 수 없는 상태에 대한 이해..
상태(State)
시간이 지남에 따라 변할 수 있는 값
ex)
- 네트워크 연결을 설정할 수 없을 때 표시되는 스낵바
- 블로그 게시물 및 관련 댓글
- 사용자가 클릭하면 버튼에서 재생되는 물결 애니메이션
- 사용자가 이미지 위에 그릴 수 있는 스티커
상태 및 구성
Composable 을 업데이트 하려면 새 인수로 동일 컴포저블을 호출해야함
컴포저블의 상태(State)
컴포저블은 remeber API 를 사용해 메모리에 객체를 저장할 수 있음
초기 컴포지션 중에 값을 저장하고
리컴포지션시에 이 값을 꺼내 사용
MutableState<T> 형식 : 관찰가능한 유형 대표(?)
관찰가능한 객체를 선언하는 세가지 방법
- val mutableState = remember { mutableStateOf(default) }
- var value by remember { mutableStateOf(default) }
- val (value, setValue) = remember { mutableStateOf(default) }
주의 : ArrayList<T>, mutableListOf() 같은 mutable 한 객체를 상태로 사용하면 관찰이 불가하여 객체 변경 시 리컴포지션이 트리거되지 않는다. State<List<T>>, listOf() 등 관찰 가능한 데이터 홀더를 사용할 것!
Remember 는 재구성(recomposition)시에 값을 저장하는 역할, 구성 변경 전반에서는 값을 저장하지 못하므로
그러한 역할이 필요할 때는 remember saveable 을 사용한다.
Remember saveable 에는 Bundle 에 저장될 수 있는 값 형태나, 맞춤 Saver 객체가 저장된다.
(번들에 추가할 수 없는 데이터 유형을 사용하고 싶은 경우 @Parcelize 주석, mapSaver, ListSaver 등을 이용하여 saver 객체를 만들어 저장할 수 있다.... 김 비둘기 님 피드백)
Jetpack Compose 에서 지원되는 기타 상태 유형
컴포즈는 state 객체를 읽어 재구성(리컴포지션)을 수행하므로 관찰 대상 데이터들을 state로 변환해주어야한다.
아래 유형들을 State<T> 로 변환하는 함수가 Compose 에 내장되어있음
- 아티팩트(디펜던시) 필요..
- 어떤 아티팩트 필요한지는 원문에서 확인하자~~ https://developer.android.com/jetpack/compose/state?hl=ko#use-other-types-of-state-in-jetpack-compose
Flow : CollectAsStateWithLifecycle() - Android 전용
Flow : CollectAsState
LiveData : ObserveAsState()
RxJava2 : subscribeAsState()
RxJava3 : subscribeAsState()
이외에 다른 유형을 컴포즈와 함께 사용하기 위해 produceState API 를 이용해 직접 확장함수를 빌드해도 된다고 한다..
스테이트풀(Stateful)과 스테이트리스(Stateless)
스테이트풀 : remember 로 객체를 저장하는 컴포저블을 스테이트풀 하다고 한다.
스테이트리스 : 내부에 state 를 갖지 않는 컴포저블(파라미터로 받아서 쓰기만..)
스테이트풀은 호출자가 상태를 제어,관리할 수 없다 -> 스테이트풀은 호출자가 상태를 제어,관리할 필요 없을 때 쓴다
스테이트풀한 컴포저블은 밖에서 스테이트를 제어, 관리 할 수 없으므로 재사용 가능성이 적고 테스터블하지 않다.
따라서 재사용을 위한 컴포저블 개발 시 스테이트풀/ 스테이트리스 모두 노출하기도 함
상태 호이스팅
컴포저블을 스테이스리스로 만들기위해 상태를 호출자로 옮기는(끌어올리는) 패턴
내부의 상태변수를 두개의 매개변수로 바꾼다
- Value : 표시될 값
- Event : 값 변경을 요청하는 이벤트
2번 Event 는 onValueChange : (T) -> Unit 형태로 많이 쓰지만 구체적 이벤트가 어울리는 경우 람다를 이용해 정의할 수 있음
끌어올려진 상태의 중요한 속성
- 단일 정보 소스 - Single Source Of Truth : 버그 방지
- 캡슐화 : 끌어올림 받은(?) 스테이트풀 컴포저블의 내부적 속성으로 이 스테이트풀 컴포저블만 상태를 수정할 수 있음
- 공유가능 : 호이스팅 후 스테이트풀 컴포저블 내부(하위의) 다른 컴포저블에도 값을 공유할 수 있다
- 가로채기 가능 : 호출자가 값을 먼저 보고 무시하거나 수정하는 등 결정이 가능
- 분리됨 : 상태를 뷰모델 등 어디든지 저장할 수 있음
이러한 호이스팅을 통해 UI 상태를 표시하는 컴포저블과 상태를 저장하고 변경하는 앱 부분을 분리할 수 있다.
상태만 mock 으로 주고 이래저래 테스트도 간편하고 좋다…
틀린내용 댓글로 달아주시면 감사합니다