Compose 및 기타 라이브러리

Compose에서는 자주 이용하는 라이브러리를 사용할 수 있습니다. 이 섹션에서는 몇 가지 가장 유용한 라이브러리를 통합하는 방법을 설명합니다.

ViewModel

아키텍처 구성요소 ViewModel 라이브러리를 사용하는 경우 viewModel() 함수를 호출하여 컴포저블에서 ViewModel에 액세스할 수 있습니다.

class ExampleViewModel : ViewModel() { /*...*/ }

@Composable
fun MyExample(
    viewModel: ExampleViewModel = viewModel()
) {
    // use viewModel here
}

viewModel()은 기존 ViewModel을 반환하거나 지정된 범위에서 새 ViewModel을 생성합니다. ViewModel은 범위가 활성화되어 있는 동안 유지됩니다. 예를 들어 컴포저블이 활동에서 사용되는 경우 viewModel()은 활동이 완료되거나 프로세스가 종료될 때까지 동일한 인스턴스를 반환합니다.

@Composable
fun MyExample(
    // Returns the same instance as long as the activity is alive,
    // just as if you grabbed the instance from an Activity or Fragment
    viewModel: ExampleViewModel = viewModel()
) { /* ... */ }

@Composable
fun MyExample2(
    viewModel: ExampleViewModel = viewModel() // Same instance as in MyExample
) { /* ... */ }

ViewModel에 종속 항목이 있는 경우 viewModel()은 선택적 ViewModelProvider.Factory를 매개변수로 사용합니다.

Compose의 ViewModel, 인스턴스가 Compose 탐색 라이브러리와 함께 사용되는 방식 또는 활동 및 프래그먼트에 관한 자세한 내용은 상호 운용성 문서를 참고하세요.

데이터 스트림

Compose에는 Android에서 가장 많이 사용되는 스트림 기반 솔루션을 위한 확장이 함께 제공됩니다. 이러한 각 확장은 다음과 같은 다양한 아티팩트에 의해 제공됩니다.

  • LiveData.observeAsState()androidx.compose.runtime:runtime-livedata:$composeVersion 아티팩트에 포함됩니다.
  • Flow.collectAsState()는 추가 종속 항목이 필요하지 않습니다.
  • Observable.subscribeAsState()androidx.compose.runtime:runtime-rxjava2:$composeVersion 또는 androidx.compose.runtime:runtime-rxjava3:$composeVersion 아티팩트에 포함됩니다.

이러한 아티팩트는 리스너로 등록되며 값을 State로 나타냅니다. 새 값이 생성될 때마다 Compose는 state.value가 사용되는 UI의 해당 부분을 재구성합니다. 예를 들어 다음 코드에서 ShowDataexampleLiveData가 새 값을 내보낼 때마다 재구성됩니다.

@Composable
fun MyExample(
    viewModel: ExampleViewModel = viewModel()
) {
    val dataExample = viewModel.exampleLiveData.observeAsState()

    // Because the state is read here,
    // MyExample recomposes whenever dataExample changes.
    dataExample.value?.let {
        ShowData(dataExample)
    }
}

Compose의 비동기 작업

Jetpack Compose를 사용하면 컴포저블 내에서 코루틴을 사용하여 비동기 작업을 실행할 수 있습니다.

자세한 내용은 부수 효과 문서에서 LaunchedEffect, produceStaterememberCoroutineScope API를 참고하세요.

Compose 프로젝트에 탐색 요소를 추가하려면 Compose 탐색 라이브러리를 사용하는 것이 좋습니다. 이 요소를 사용하면 탐색 구성요소의 인프라와 기능을 활용하면서 컴포저블 간에 이동하기 위한 UI를 추가할 수 있습니다.

이 통합에 관한 자세한 내용은 Compose를 통해 이동 문서를 참고하세요.

Hilt

Hilt는 Android 앱에서 종속 항목 삽입을 위해 권장되는 솔루션이며 Compose와 함께 원활하게 작동합니다.

ViewModel 섹션에서 언급된 viewModel() 함수는 Hint에서 @HiltViewModel 주석을 사용하여 구성하는 ViewModel을 자동으로 사용합니다. 자세한 내용은 Hilt의 ViewModel 통합에 관한 문서를 참고하세요.

@HiltViewModel
class ExampleViewModel @Inject constructor(
    private val savedStateHandle: SavedStateHandle,
    private val repository: ExampleRepository
) : ViewModel() { /* ... */ }

@Composable
fun ExampleScreen(
    exampleViewModel: ExampleViewModel = viewModel()
) { /* ... */ }

Hilt 및 탐색

Hilt는 Compose 탐색 라이브러리와도 통합됩니다. Gradle 파일에 다음과 같은 종속 항목을 추가합니다.

app/build.gradle

...
dependencies {
  ...
  implementation 'androidx.hilt:hilt-navigation-compose:1.0.0-alpha03'
}

@HiltViewModel 주석이 달린 ViewModel탐색 그래프로 범위가 지정되면 @AndroidEntryPoint로 주석이 달린 프래그먼트나 활동과 함께 작동하는 hiltViewModel 구성 가능한 함수를 사용합니다.

예를 들어 ExampleScreen이 탐색 그래프의 대상이면 hiltViewModel()을 호출하여 아래 코드 스니펫과 같이 해당 대상으로 범위가 지정된 ExampleViewModel의 인스턴스를 가져옵니다.

// import androidx.hilt.navigation.compose.hiltViewModel

@Composable
fun MyApp() {
    NavHost(navController, startDestination = startRoute) {
        composable("example") { backStackEntry ->
            // Creates a ViewModel from the current BackStackEntry
            // Available in the androidx.hilt:hilt-navigation-compose artifact
            val exampleViewModel = hiltViewModel<ExampleViewModel>()
            ExampleScreen(exampleViewModel)
        }
        /* ... */
    }
}

대신 탐색 경로로 범위가 지정된 ViewModel의 인스턴스를 검색해야 한다면 대상 루트를 매개변수로 전달합니다.

// import androidx.hilt.navigation.compose.hiltViewModel
// import androidx.navigation.compose.getBackStackEntry

@Composable
fun MyApp() {
    NavHost(navController, startDestination = startRoute) {
        navigation(startDestination = innerStartRoute, route = "Parent") {
            // ...
            composable("exampleWithRoute") { backStackEntry ->
                val parentEntry = remember {
                  navController.getBackStackEntry("Parent")
                }
                val parentViewModel = hiltViewModel<ParentViewModel>(
                  parentEntry
                )
                ExampleWithRouteScreen(parentViewModel)
            }
        }
    }
}

Paging

Paging 라이브러리를 사용하면 데이터를 점진적이고 매끄럽게 로드할 수 있으며 Paging 라이브러리는 Compose에서 지원됩니다. Paging 출시 페이지에는 프로젝트에 추가해야 하는 추가 paging-compose 종속 항목 및 버전에 관한 정보가 포함되어 있습니다.

다음은 Paging 라이브러리의 Compose API의 예입니다.

@Composable
fun MyExample(flow: Flow<PagingData<String>>) {
    val lazyPagingItems = flow.collectAsLazyPagingItems()
    LazyColumn {
        items(lazyPagingItems) {
            Text("Item is $it")
        }
    }
}

Compose에서 Paging을 사용하는 것에 관한 자세한 내용은 목록 문서를 참고하세요.

이미지 로드

Instacart의 Coil 라이브러리는 네트워크를 통해 원격 이미지를 로드하는 등 외부 소스에서 이미지를 로드하는 구성 가능한 함수를 제공합니다.

다음은 io.coil-kt:coil-compose 아티팩트의 rememberImagePainter 예입니다.

@Composable
fun MyExample() {
    val painter = rememberImagePainter(
        data = "https://picsum.photos/300/300",
        builder = {
            crossfade(true)
        }
    )

    Box {
        Image(
            painter = painter,
            contentDescription = stringResource(R.string.image_content_desc),
        )

        when (painter.state) {
            is ImagePainter.State.Loading -> {
                // Display a circular progress indicator whilst loading
                CircularProgressIndicator(Modifier.align(Alignment.Center))
            }
            is ImagePainter.State.Error -> {
                // If you wish to display some content if the request fails
            }
        }
    }
}