Compose State

객체의 어떠한 값 또는 데이터

Compose State

State


안드로이드에서 앱은 사용자에게 상태를 표시하는데 “네트워크를 연결할 수 없을 때의 메시지 표시”, “사용자가 클릭하면 발생하는 애니메이션” 등을 말하며 상태는 컴포즈에서 가장 중요한 개념이다.

remember

컴포저블은 중단되거나, 새로 그려지거나, 여러 스레드에서 여러 컴포저블을 계산하고 합쳐서 하나의 UI 를 만든다던지 등 언제든지 상태가 저장되지 않고 지워질 수 있는데 remember 를 사용하면 상태를 기억했다가 나중에 다시 사용할 수 있다.

remember 를 사용해서 메모리에 단일 객체를 저장할 수 있으며 remember 에 의해 컴포지션에 저장되고 저장된 값은 리컴포지션 중에 반환되어 상태가 업데이트 된다.

// 해당 코드를 실행하면 텍스트를 입력해도 아무런 반응이 없다.
@Composable
fun Input1() {
    Column(modifier = Modifier.padding(10.dp)) {
        Text(text = "Hello")
            OutlinedTextField(
            value = "",
            onValueChange = { },
            label = { Text("Name") }
        )
    }
}

// 해당 코드를 실행하면 텍스트를 입력하면 동작한다.
@Composable
fun Input2() {
    Column(modifier = Modifier.padding(10.dp)) {
        val name by remember { mutableStateOf("") }
    
        Text(text = "Hello")
            OutlinedTextField(
            value = name,
            onValueChange = { name = it },
            label = { Text("Name") }
        )
    }
}


mutableStateOf

컴포즈에서는 다시 그려지는 과정이 반복되는데, UI 가 갱신되기 위해서는 리컴포지션이 발생해야하며 리컴포지션이 발생하기 위해서는 상태가 바뀌어야 하는데, 여기서 상태는 코드로는 mutableStateOf 를 말한다.

interface MutableState<T> : State<T> {
   override var value: T
}
  • mutableStateOf 는 컴포즈에서 Observable 타입인 MutableState 를 생성하는데 value 가 변경되면 그 값을 읽는 컴포저블 함수의 리컴포지션이 발생하게 된다.

val checked1 = remember { mutableStateOf(false) }
val checked2 by remember { mutableStateOf(false) }
val (checked3, setChecked3) = remember { mutableStateOf(false) }
  • by 키워드를 통해 위임된 속성(delegated properties)을 사용하면 value 프로퍼티 자체인 것처럼 사용할 수 있는데 예를 들면, checkedchecked.value 프로퍼티 인것 처럼 사용이 가능하다.
  • 비구조화(destruction)를 통해 상태를 받아와 처리하는 것도 가능한데, mutableStateOf 의 반환형인 MutableStategettercomponent1()settercomponent2() 를 받아오는 것을 의미한다.

rememberSaveable

remember 는 리컴포지션이 발생할 경우에 상태를 유지할 수 있도록 도움을 주지만 화면 회전과 같은 Configuration 이 변경되는 경우에는 유지가 되지 않아 rememberSaveable 을 사용해야 한다.

rememberSaveableBundle 에 저장할 수 있는 모든 값을 자동으로 저장하는데, 저장 공간에 한계가 있기 때문에 모든 값에 rememberSaveable 를 적용하는 것은 권장되지 않는다.

val checked by rememberSaveable { mutableStateOf(false) }



State Hosting


State Hosting 은 컴포저블의 상태를 다른 컴포저블이나 호출하는 함수로 옮기는 패턴을 말하며, 이를 통해 컴포저블을 상태를 가지지 않는(Stateless) 형태로 만들 수 있게 된다.

UI 부분은 상태가 없게 만들고, 상태가 변경되는 코드를 따로 관리하는 것이 권장되는 방법이다.

@Composable
fun PyeongToSquareMeter() {
    var pyeong by rememberSaveable {
        mutableStateOf("23")
    }
    var squaremeter by rememberSaveable {
        mutableStateOf((23 * 3.306).toString())
    }

    PyeongToSquareMeterStateless(
        pyeong = pyeong,
        squaremeter = squaremeter,
        onPyengChange = {
            if (it.isBlank()) {
                pyeong = ""
                squaremeter = ""
                return@PyeongToSquareMeterStateless
            }
            val numericValue = it.toFloatOrNull() ?: return@PyeongToSquareMeterStateless
            pyeong = it
            squaremeter = (numericValue * 3.306).toString()
        }
    )
}

@Composable
fun PyeongToSquareMeterStateless(
    pyeong: String,
    squaremeter: String,
    onPyengChange: (String) -> Unit
) {
    Column(modifier = Modifier.padding(16.dp)) {
        OutlinedTextField(
            value = pyeong,
            onValueChange = onPyengChange,
            label = {
                Text("평")
            }
        )
        OutlinedTextField(
            value = squaremeter,
            onValueChange = {},
            label = {
                Text("제곱미터")
            }
        )
    }
}



Compose Observable Type


컴포즈에서 상태 관리를 위해 MutableState<T> 를 사용할 필요 없이 기존의 Livedata, Flow 등을 사용할 수 있다.

Livedata 와 같은 다른 Observable 타입을 사용할 경우에 Livedata<T>.observeAsState() 와 같은 컴포저블 함수를 사용해서 State<T> 로 변환하여 상태를 읽어올 수 있으며, 그래야 상태가 변할 때 자동으로 리컴포지션이 발생하게 된다.

observeAsState() 와 같은 State<T> 로 변환해주는 컴포저블 함수는 컴포지션에 있는 동안에만 해당 데이터 홀더를 관찰한다.

essential