[Android] Compose에서 State 생성 방법

문승연·2024년 3월 31일
0
post-thumbnail

State란?

Jetpack Compose에서는 UI의 상태가 변했음을 인식하기 위해 State를 사용한다.

Composable UI가 특정 변수를 State로 인식하기 위해서는 mutableStateOf 같은 State Object로 감싸주면된다.

State Object로 활용하는 방법에는 mutableStateOf 말고도 여러가지 방법이 있다. 이번 포스트에서는 각 방법들에 대해 알아보고 어떤 차이점이 있는지 알아보도록 하겠다.

LiveData

기존의 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

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) }

MutableStateFlow

StateFlow, MutableStateFlow는 위의 MutableStateOf와는 조금 다르게 Kotlin Coroutine의 Flow를 State로 사용하기 위한 API이다.

일반적인 Flow와 차이점은 StateFlowHot 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 to Compose State

RxJava도 Compose State로 변환할 수 있다. subscribeAsState() 메소드로 변환해주면 된다.

레퍼런스

  1. 안드로이드 공식 문서 State and Jetpack Compose
  2. 코틀린 공식 문서 StateFlow
  3. mutableStateOf와 MutableStateFlow 비교 총 정리 #collectAsState
profile
"비몽(Bemong)"이라는 앱을 개발 및 운영 중인 안드로이드 개발자입니다.

0개의 댓글