Compose 和其他库

您可以在 Compose 中使用自己喜欢的库。本部分介绍了如何纳入一些最有用的库。

ViewModel

如果您使用 Architecture Components ViewModel 库,可以通过调用 viewModel() 函数,从任何可组合项访问 ViewModel

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

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

viewModel() 会返回一个现有的 ViewModel,或在给定作用域内创建一个新的 ViewModel。只要该作用域处于有效状态,就会保留 ViewModel。例如,如果在某个 Activity 中使用了可组合项,则在该 Activity 完成或进程终止之前,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 Navigation 库或 activity 和 fragment 一起使用,请参阅互操作性文档

数据流

Compose 随附了一些扩展程序,它们适用于最热门的基于流的 Android 解决方案。其中每个扩展程序都由不同的工件提供:

这些工件注册为监听器,并将值表示为 State。每当发出一个新值时,Compose 都会重组界面中使用该 state.value 的部分。例如,在以下代码中,每当 exampleLiveData 发出一个新值时,ShowData 都会重组。

@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,您可以从可组合项中使用协程执行异步操作。

如需了解详情,请参阅附带效应文档中的 LaunchedEffectproduceStaterememberCoroutineScope API。

我们建议您使用 Compose Navigation 库向 Compose 项目添加导航元素。通过这些元素,您可以添加界面,以便在利用导航组件的基础架构和功能时,在可组合项之间导航。

如需详细了解此集成,请参阅使用 Compose 导航文档。

Hilt

建议使用 Hilt 解决方案在 Android 应用中实现依赖项注入,并且 Hilt 能与 Compose 无缝协作。

ViewModel 部分提及的 viewModel() 函数自动使用 Hilt 通过 @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 和 Navigation

Hilt 还与 Compose Navigation 库集成。请将下面这些额外的依赖项添加到 Gradle 文件中:

app/build.gradle

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

如果带有 @HiltViewModel 注解的 ViewModel 的作用域限定为导航图,请使用 hiltViewModel 可组合函数,该函数可与带有 @AndroidEntryPoint 注解的 fragment 或 activity 搭配使用。

例如,如果 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 库,您可以更加轻松地逐步加载数据,且该库在 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 的 Cil 库提供用于从外部来源加载图片(例如通过网络加载远程图片)的可组合函数。

下面是一个关于 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
            }
        }
    }
}