Jetpack Compose에서는 UI의 상태가 변했음을 인식하기 위해 State
를 사용한다.
Composable UI
가 특정 변수를 State
로 인식하기 위해서는 mutableStateOf
같은 State Object로 감싸주면된다.
State Object로 활용하는 방법에는 mutableStateOf
말고도 여러가지 방법이 있다. 이번 포스트에서는 각 방법들에 대해 알아보고 어떤 차이점이 있는지 알아보도록 하겠다.
기존의 MVVM 패턴에서 ViewModel
이 갖고있는 데이터를 UI Layer에서 관찰하기 위해서는 LiveData
를 사용했다.
하지만 State
, MutableState
가 Compose에 좀 더 특화되어있기 때문에 Compose로 UI를 구성한 프로젝트에서는 ViewModel
을 사용할 때 State
를 사용한다.
물론 Compose로 구성된 프로젝트에서도 LiveData
를 사용할 수는 있다. 하지만 이를 Composable에서 State로 인식하기 위해서는 observeAsState
메소드를 통해 State로 변환해주어야한다.
class TermModel : ViewModel() {
private val termList = mutableStateListOf<Term>()
private val termListLiveData: MutableLiveData<List<Term>> = MutableLiveData()
...
}
@Composable
fun test(){
val list by termModel.termListLiveData.observeAsState(listOf())
LazyColumn(
modifier = Modifier
.fillMaxSize()
.background(Color(0xDE, 0xDE, 0xDE, 0xFF))
.clickable(onClick = {
//when i click the whole list, it delete the last element of list, and then automatically update view
list.deleteLast()
}),
verticalArrangement = Arrangement.spacedBy(10.dp)
) {
items(list) {
Text(text = it)
}
}
}
mutableStateOf
는 Observable한 MutableState<T>
를 생성해준다. 이 MutableState<T>
값이 변경될 때마다 컴포저블 함수가 Recompose 된다.
특정한 값 그 자체를 State
로 쓰고 싶을때 사용할 수 있다.
class NameViewModel : ViewModel() {
var name by mutableStateOf<String>()
}
@Composable
fun NameScreen() {
Text(
text = viewModel.name
)
}
MutableState
를 선언하는 방법은 위의 예시 외에도 총 3가지가 있다.
val mutableState = remember { mutableStateOf(default) }
var value by remember { mutableStateOf(default) }
val (value, setValue) = remember { mutableStateOf(default) }
StateFlow
, MutableStateFlow
는 위의 MutableStateOf
와는 조금 다르게 Kotlin Coroutine의 Flow
를 State로 사용하기 위한 API이다.
일반적인 Flow와 차이점은 StateFlow
는 Hot Stream이라는 것이다. 즉, collector
의 존재여부에 상관없이 독립적으로 값을 방출한다.
그리고 또 다른 점은 절대 complete
이 일어나지 않는다는 점이다.
class CounterModel {
private val _counter = MutableStateFlow(0) // private mutable state flow
val counter = _counter.asStateFlow() // publicly exposed as read-only state flow
fun inc() {
_counter.update { count -> count + 1 } // atomic, safe for concurrent use
}
}
StateFlow
, MutableStateFlow
를 Compose에서 State로 활용하기 위해서는 collectAsState
또는 collectAsStateWithLifecycle
메소드로 변환해줘야한다.
이때 생명주기에 따른 데이터 손실을 방지하기 위해서 collectAsStateWithLifecycle
을 사용하는 게 좀 더 바람직하다.
대신 collectAsState
는 platform-agnostic한 코드에서 사용하면 된다. (collectAsStateWithLifecycle
은 안드로이드 플랫폼 한정에서만 동작한다.)
RxJava도 Compose State
로 변환할 수 있다. subscribeAsState()
메소드로 변환해주면 된다.
레퍼런스