Android

Android | Jetpack Compose State & Event

8iggy 2022. 12. 5. 00:35

읽기 전

  • 불필요한 코드나 잘못 작성된 내용에 대한 지적은 언제나 환영합니다.
  • 개인적으로 실습하면서 배운 점을 정리한 글입니다,

Jetpack Compose의 State 코드랩Jetpack Compose State 공식문서의 내용을 정리합니다. UI를 결정짓는 State와 State 변경을 위해 트리거되는 Event에 대해 정의합니다.

Composition 관련 용어

  • 컴포지션(Composition): Jetpack Compose가 Composable 함수를 실행할 때 빌드한 UI
  • 초기 첨포지션(Initial Composition): 처음 Composable을 실행하여 Composition 생성
  • 리컴포지션(Recomposition): 상태 변경 시 Composition을 업데이트하기 위해 Composable을 다시 실행하는 과정

State란?

시간이 지남에 따라 변할 수 있는 값으로 광범위하게 정의되어 있다. Room DB 데이터부터 클래스 변수까지 포괄하기 때문이다. 요약하자면, 상태에 따라 특정 시점에 앱 UI에 표시되는 항목이 결정된다고 이해하면 된다.

  • State 예시
    • 채팅앱 최근 수신 메세지
    • 사용자의 프로필 사진
    • 목록의 스크롤 위치

State & Event & Composition

Compose는 선언형이므로 Compose 업데이트를 위해서는 새로운 인수로 동일 컴포저블을 호출해야 한다. 그리고 해당 "인수"는 UI 상태를 표현한다. 상태가 업데이트되면 재구성(Recomposition)이 발생한다.

우선 특정 카운트를 표시하는 Composable 함수를 생성하고 Activity에 설정한다.

WaterCounter.kt

@Composable
fun WaterCounter(modifier: Modifier = Modifier) {
   val count = 0
   Text(
       text = "You've had $count glasses.",
       modifier = modifier.padding(16.dp)
   )
}

몇 잔의 물을 마셨는지 출력하는 텍스트 컴포저블을 정의하였다.

WellnessScreen.kt

@Composable
fun WellnessScreen(modifier: Modifier = Modifier) {
   WaterCounter(modifier)
}

얼마나 마셨는지 출력하는 WaterCounter 컴포저블 함수를 출력하는 Screen 함수이다.

MainActivity.kt

class MainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           // 프로젝트 이름에 따라 변경되는 Theme
           BasicStateCodelabTheme {
               // A surface container using the 'background' color from the theme
               Surface(
                   modifier = Modifier.fillMaxSize(),
                   color = MaterialTheme.colors.background
               ) {
                   WellnessScreen()
               }
           }
       }
   }
}

실행결과

Android_Jetpack_Compose_State_Event_001

물을 얼마나 마셨는지 표시하는 WaterCounter 함수는 count 변수의 상태에 따라 결정된다. 버튼을 정의해서 count 변수를 증가시켜 보자.

Compose Event

상태의 업데이트는 이벤트에 대한 응답 기반으로 이루어진다. 흔히 버튼 누르기 등 UI 요소와 사용자 간의 상호작용이나 네트워크 응답 등으로 트리거된다. 이에 공식문서는 다음과 같이 상태와 이벤트를 표현한다.

상태는 존재하고 이벤트는 발생한다.

Android는 다음 그림으로 표현되는 핵심 UI 업데이트 루프를 갖는다.

Android_Jetpack_Compose_State Event_002

  • 이벤트: 사용자 및 기타 요인에 의해 발생
  • 상태 업데이트: 이벤트 핸들러가 UI에서 사용하는 상태를 변경
  • 상태 표시: 새로운 상태를 표시하도록 UI가 업데이트 됨

사용자가 상호작용할 수 있도록 버튼을 정의하여 count 변수가 증가게끔 설정한다.

WaterCounter.kt

@Composable
fun WaterCounter(modifier: Modifier = Modifier) {
   Column(modifier = modifier.padding(16.dp)) {
       var count = 0
       Text("You've had $count glasses.")
       Button(
           onClick = { count++ },
           Modifier.padding(top = 8.dp)
       ) {
           Text("Add one")
       }
   }
}

사용자가 이벤트를 발생시키도록 버튼을 정의하였고 클릭 시 상태인 count 변수를 증가시켰으나 아무 일도 일어나지 않는다.

Android_Jetpack_Compose_State Event_003

count 변수에 다른 값이 설정되어도 Compose에서 해당 변수의 값 변경을 "상태 변경"으로 감지하지 않았기에 UI 업데이트(컴포저블 함수의 재구성 즉, Recomposition)가 일어나지 않는다. 상태가 변경될 때 Compose에 화면을 다시 그려야 한다고 알리지 않았기 때문이다.

참고자료

  1. Google Codelab - Jetpack Compose의 상태 #3 Compose에서의 상태
  2. Google Codelab - Jetpack Compose의 상태 #4 Compose에서의 이벤트
  3. Android Developers - 상태 및 Jetpack Compose