Jetpack Compose | Composable 함수에서의 ViewModel 사용

J
implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.5.1

Jetpack Compose의 Composable 함수에서 viewModel() 함수로 뷰 모델에 액세스 하기 위해 앱 단위 build.gradle 에 다음 라이브러리를 추가한다.

@Composable
fun Test(testViewModel: TestViewModel = viewModel()) {
    Text(text = testViewModel.str)
}

라이브러리 추가 이후 Jetpack Compose로 UI를 구성하는 과정에서 다음과 같이 ViewModel을 참조할 수 있다. 그러나 매개 변수로 전달된 View Model을 하위 Composable 함수에 전달 해서는 안 된다. 안드로이드 문서에서도 화면수준의 컴포저블 함수 (보통 우리가 -Screen이라고 선언하는 컴포저블 함수를 말하는 듯하다)에서 함수를 호출하고 액세스해야 한다고 명시하고 있다.

이와 같은 이유로 다음과 같은 형태의 ViewModel 활용은 Jetpack Compose로 모든 화면이 구성된 앱을 개발할 때 효과적일 것으로 보인다. 기존의 UI와 함께 사용하는 앱에서는 이미 Fragment 나 Activity 단위로 ViewModel이 구성된 상황일 것이다. 그뿐만 아니라 실제로 사용하기 전에는 Compose 에 붙어있는 ViewModelStoreOwner가 언제 생성되고 소멸하는지 확실히 파악할 필요가 있어 보인다.

하위 Composable 함수로 값을 전달해야 할 때는, 기존에 상태를 호이스팅 하는 것처럼 하위 Composable 함수로 값을 전달 하는 것이 좋아 보인다. Composable 함수를 View Model과 함께 사용하면 자주 겪는 어려움은 Preview를 구성하는 데 있다. 위 코드와 같이 간단한 정적 변숫값을 출력하는 것은 문제가 없으나 DB에 접근하거나 네트워크 작업을 하는 등 프리뷰 렌더링이 어려운 경우가 있는데, 이 경우에는 Preview 가능한 Composable 함수와 우리가 실제로 앱 화면을 구성하는 데 사용하는 부분을 분리할 필요가 있다.

@Preview
@Composable
private fun TestScreenPreview() {
    TestScreen(str = "Test Screen")
}

@Composable
fun TestScreen(testViewModel: TestViewModel = viewModel()) {
    TestScreen(testViewModel.str)
}

@Composable
private fun TestScreen(str: String) {
    Text(text = str)
}

다음과 같이 실제로 화면만 구성하는(매개변수로 값을 받아 출력만 하는) Composable 함수와 실제로 View Model을 참조하는 Composable 함수 (외부에서는 이 함수만 접근 가능하므로 실제 코드 작성 시에는 이 함수가 사용된다), Preview를 구성하는 Composable 함수로 각각 분리하면 View Model의 동작과 Preview의 동작은 분리되어 자유로워진다.

비단 이 문제는 View Model을 사용할 때 이외에도 Jetpack Compose로 UI를 구성할 때 Preview를 온전히 활용하려면 모든 View Model에서, 다음과 비슷한 방식으로 구성해야 할 것으로 보인다.

@Preview(showBackground = true, device = Devices.PIXEL_2_XL)
@Composable
fun PlaylistItemPreview() {
    PlaylistItem(
        playlistData = PlaylistData(
            id = UUID.randomUUID().toString(),
            name = "이름",
            desc = "설명",
            state = "state",
            authorUid = "authorUid",
            likeCount = 0,
            resourcesCount = 0,
            createdTimestamp = null,
            authorProfile = null, thumbnailImageUrls = null
        )
    )
}

이 코드는 실제로 내가 앱에서 리스트의 아이템에 Preview를 위한 내용을 따로 구성하기 위해 작성하는 코드이다.

About the author

Gyeongrok Kim

Add comment

Your sidebar area is currently empty. Hurry up and add some widgets.