您可以在 Compose 中使用您最喜欢的库。本节介绍如何整合一些最有用的库。
Activity
要在 Activity 中使用 Compose,您必须使用 ComponentActivity
,它是 Activity
的子类,它为 Compose 提供了合适的 LifecycleOwner
和组件。它还提供其他 API,这些 API 将您的代码与覆盖 Activity 类中的方法解耦。 Activity Compose 将这些 API 公开给可组合项,因此不再需要在可组合项之外覆盖方法或检索显式 Activity
实例。此外,这些 API 确保它们只初始化一次,在重新组合后仍然存在,并且如果可组合项从组合中移除,则会正确清理。
Activity Result
rememberLauncherForActivityResult()
API 允许您在可组合项中 获取 Activity 的结果
@Composable fun GetContentExample() { var imageUri by remember { mutableStateOf<Uri?>(null) } val launcher = rememberLauncherForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? -> imageUri = uri } Column { Button(onClick = { launcher.launch("image/*") }) { Text(text = "Load Image") } Image( painter = rememberAsyncImagePainter(imageUri), contentDescription = "My Image" ) } }
此示例演示了一个简单的 GetContent()
合同。点击按钮将启动请求。 rememberLauncherForActivityResult()
的尾随 lambda 在用户选择图像并返回到启动 Activity 后被调用。这使用 Coil 的 rememberImagePainter()
函数加载选定的图像。
ActivityResultContract
的任何子类都可以用作 rememberLauncherForActivityResult()
的第一个参数。这意味着您可以使用此技术请求框架中的内容以及其他常见模式。您还可以创建自己的 自定义合同 并使用此技术。
请求运行时权限
上面解释的相同 Activity Result API 和 rememberLauncherForActivityResult()
可用于 请求运行时权限,使用 RequestPermission
合同用于单个权限或 RequestMultiplePermissions
合同用于多个权限。
Accompanist Permissions 库 也可以用作这些 API 之上的一个层,以将权限的当前授予状态映射到 Compose UI 可以使用的 State。
处理系统后退按钮
要 提供自定义后退导航 并覆盖可组合项中系统后退按钮的默认行为,您的可组合项可以使用 BackHandler
来拦截该事件
var backHandlingEnabled by remember { mutableStateOf(true) } BackHandler(backHandlingEnabled) { // Handle back press }
第一个参数控制 BackHandler
当前是否启用;您可以使用此参数根据组件的状态临时禁用处理程序。如果用户触发系统后退事件并且 BackHandler
当前已启用,则将调用尾随 lambda。
ViewModel
如果您使用 架构组件 ViewModel 库,您可以通过调用 viewModel()
函数从任何可组合项访问 ViewModel
。将以下依赖项添加到您的 Gradle 文件中
Groovy
dependencies { implementation 'androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5' }
Kotlin
dependencies { implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.8.5") }
然后您可以在代码中使用 viewModel()
函数。
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { // use viewModel here }
viewModel()
返回现有的 ViewModel
或创建一个新的。默认情况下,返回的 ViewModel
的作用域为包含的 Activity、Fragment 或导航目标,并在作用域存续期间保留。
例如,如果可组合项在 Activity 中使用,则 viewModel()
返回相同的实例,直到 Activity 结束或进程被终止。
class MyViewModel : ViewModel() { /*...*/ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( // Returns the same instance as long as the activity is alive, // just as if you grabbed the instance from an Activity or Fragment viewModel: MyViewModel = viewModel() ) { /* ... */ } @Composable fun MyScreen2( viewModel: MyViewModel = viewModel() // Same instance as in MyScreen ) { /* ... */ }
使用指南
您通常在屏幕级可组合项(即靠近从 Activity、Fragment 或导航图的目标调用的根可组合项)访问 ViewModel
实例。这是因为 ViewModel
默认情况下作用域为这些屏幕级对象。在此处阅读有关 ViewModel
的生命周期和作用域的更多信息。
尝试避免将 ViewModel
实例传递给其他可组合项,因为这会使这些可组合项更难以测试,并且可能会破坏 预览。相反,只将它们需要的 数据和函数作为参数传递。
您可以使用 ViewModel
实例来管理子屏幕级可组合项的状态,但是,请注意 ViewModel
的生命周期和作用域。如果可组合项是自包含的,您可能需要考虑使用 Hilt 来注入 ViewModel
以避免必须从父可组合项传递依赖项。
如果您的 ViewModel
有依赖项,则 viewModel()
将 ViewModelProvider.Factory
作为可选参数。
有关 Compose 中 ViewModel
以及如何将实例与 Navigation Compose 库或 Activity 和 Fragment 一起使用的更多信息,请参阅 互操作性文档。
数据流
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 部分。例如,在此代码中,每当 exampleLiveData
发出新值时,ShowData
都会重新组合。
// import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { val dataExample = viewModel.exampleLiveData.observeAsState() // Because the state is read here, // MyScreen recomposes whenever dataExample changes. dataExample.value?.let { ShowData(dataExample) } }
Compose 中的异步操作
Jetpack Compose 允许您在可组合项中使用协程执行异步操作。
有关更多信息,请参阅 副作用文档中的 LaunchedEffect
、produceState
和 rememberCoroutineScope
API。
导航
导航组件 为 Jetpack Compose 应用程序提供支持。有关更多信息,请参阅 使用 Compose 进行导航 和 将 Jetpack Navigation 迁移到 Navigation Compose。
Hilt
Hilt 是 Android 应用中依赖项注入的推荐解决方案,并且与 Compose 完美配合。
ViewModel 部分中提到的 viewModel()
函数会自动使用 Hilt 使用 @HiltViewModel
注释构建的 ViewModel。我们提供了包含有关 Hilt 的 ViewModel 集成的信息的文档。
@HiltViewModel class MyViewModel @Inject constructor( private val savedStateHandle: SavedStateHandle, private val repository: ExampleRepository ) : ViewModel() { /* ... */ } // import androidx.lifecycle.viewmodel.compose.viewModel @Composable fun MyScreen( viewModel: MyViewModel = viewModel() ) { /* ... */ }
Hilt 和 Navigation
Hilt 还与 Navigation Compose 库集成。将以下其他依赖项添加到您的 Gradle 文件中
Groovy
dependencies { implementation 'androidx.hilt:hilt-navigation-compose:1.2.0' }
Kotlin
dependencies { implementation("androidx.hilt:hilt-navigation-compose:1.2.0") }
使用 Navigation Compose 时,始终使用 hiltViewModel
可组合函数来获取 @HiltViewModel
注释的 ViewModel
的实例。这适用于使用 @AndroidEntryPoint
注释的 Fragment 或 Activity。
例如,如果ExampleScreen
是导航图中的目标位置,请调用hiltViewModel()
获取ExampleViewModel
的实例,该实例的作用域限定在目标位置,如下面的代码片段所示。
// import androidx.hilt.navigation.compose.hiltViewModel @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" NavHost(navController, startDestination = startRoute) { composable("example") { backStackEntry -> // Creates a ViewModel from the current BackStackEntry // Available in the androidx.hilt:hilt-navigation-compose artifact val viewModel = hiltViewModel<MyViewModel>() MyScreen(viewModel) } /* ... */ } }
如果您需要检索作用域限定在导航路由或导航图的ViewModel
实例,请使用hiltViewModel
组合函数并将相应的backStackEntry
作为参数传递。
// import androidx.hilt.navigation.compose.hiltViewModel // import androidx.navigation.compose.getBackStackEntry @Composable fun MyApp() { val navController = rememberNavController() val startRoute = "example" val innerStartRoute = "exampleWithRoute" NavHost(navController, startDestination = startRoute) { navigation(startDestination = innerStartRoute, route = "Parent") { // ... composable("exampleWithRoute") { backStackEntry -> val parentEntry = remember(backStackEntry) { navController.getBackStackEntry("Parent") } val parentViewModel = hiltViewModel<ParentViewModel>(parentEntry) ExampleWithRouteScreen(parentViewModel) } } } }
分页
Paging 库使您能够更轻松地逐步加载数据,并且在 Compose 中受支持。Paging 发布页面包含有关需要添加到项目中的额外paging-compose
依赖项及其版本的信息。
以下是以 Paging 库的 Compose API 为例。
@Composable fun MyScreen(flow: Flow<PagingData<String>>) { val lazyPagingItems = flow.collectAsLazyPagingItems() LazyColumn { items( lazyPagingItems.itemCount, key = lazyPagingItems.itemKey { it } ) { index -> val item = lazyPagingItems[index] Text("Item is $item") } } }
查看列表和网格文档,以获取有关在 Compose 中使用 Paging 的更多信息。
地图
您可以使用Maps Compose库在您的应用中提供 Google 地图。以下是一个使用示例。
@Composable fun MapsExample() { val singapore = LatLng(1.35, 103.87) val cameraPositionState = rememberCameraPositionState { position = CameraPosition.fromLatLngZoom(singapore, 10f) } GoogleMap( modifier = Modifier.fillMaxSize(), cameraPositionState = cameraPositionState ) { Marker( state = remember { MarkerState(position = singapore) }, title = "Singapore", snippet = "Marker in Singapore" ) } }
为您推荐
- 注意:当 JavaScript 关闭时,会显示链接文本。
- Compose 中的副作用
- 状态和 Jetpack Compose
- 在 Compose 中保存 UI 状态