在 Compose 中,界面是不可变的,在绘制后无法进行更新。您可以控制的是界面的状态。每当界面的状态发生变化时,Compose 都会重新创建界面树中已更改的部分。可组合项可以接受状态并公开事件,例如 TextField
接受值并公开请求回调处理程序更改值的回调 onValueChange
。
var name by remember { mutableStateOf("") } OutlinedTextField( value = name, onValueChange = { name = it }, label = { Text("Name") } )
由于可组合项接受状态并公开事件,因此单向数据流模式非常适合 Jetpack Compose。本指南将重点介绍如何在 Compose 中实现单向数据流模式,如何实现事件和状态容器,以及如何在 Compose 中使用 ViewModel。
单向数据流
单向数据流 (UDF) 是一种设计模式,在该模式下状态向下流动,事件向上流动。通过采用单向数据流,您可以将在界面中显示状态的可组合项与应用中存储和更改状态的部分分离开来。
使用单向数据流的应用的界面更新循环如下所示:
- 事件:界面的某一部分生成一个事件,并将其向上传递,例如将按钮点击传递给 ViewModel 进行处理;或者从应用的其他层传递事件,如指示用户会话已过期。
- 更新状态:事件处理脚本可能会更改状态。
- 显示状态:状态容器向下传递状态,界面显示此状态。

使用 Jetpack Compose 时遵循此模式可带来下面几项优势:
- 可测试性:将状态与显示状态的界面分离开来,更方便单独对二者进行测试。
- 状态封装:因为状态只能在一个位置进行更新,并且可组合项的状态只有一个可信来源,所以不太可能由于状态不一致而出现 bug。
- 界面一致性:通过使用可观察的状态容器,例如
StateFlow
或LiveData
,所有状态更新都会立即反映在界面中。
Jetpack Compose 中的单向数据流
可组合项基于状态和事件进行工作。例如,只有在更新其 value
参数并公开 onValueChange
回调(这是一个请求将值更改为新值的事件)时,TextField
才会更新。Compose 将 State
对象定义为值容器,而对状态值的更改会触发重组。您可以将状态保存在 remember { mutableStateOf(value) }
或 rememberSaveable { mutableStateOf(value)
中,具体取决于您需要记住值的时长。
TextField
可组合项的值的类型为 String
,因此该值可以来自任意位置,包括来自硬编码值、ViewModel 或从父级可组合项传入。您不必将它保存在 State
对象中,但在调用 onValueChange
时需要更新该值。
定义可组合项参数
在定义可组合项的状态参数时,您应牢记以下问题:
- 可组合项的可重用性或灵活性如何?
- 状态参数如何影响此可组合项的性能?
为了促进分离和重复使用,每个可组合项都应包含尽可能少的信息。例如,构建可组合项以保存新闻报道的标题时,最好仅传递需要显示的信息,而不是整篇新闻报道:
@Composable fun Header(title: String, subtitle: String) { // Recomposes when title or subtitle have changed. } @Composable fun Header(news: News) { // Recomposes when a new instance of News is passed in. }
有时,使用独立参数还能提高性能,例如,如果 News
包含的不仅仅是 title
和 subtitle
的信息,每当有 News
的新实例传入 Header(news)
时,即使 title
和 subtitle
没有变化,可组合项也将重组。
请仔细考虑传入的参数数量。如果一个函数拥有过多参数,会降低该函数的工效,因此在这种情况下,建议您将这些参数分到一个类下。
Compose 中的事件
应用的每项输入都应表示为事件:点按、文本更改,甚至计时器或其他更新。随着这些事件更改界面的状态
ViewModel
应负责处理它们并更新界面状态。
界面层绝不应更改事件处理脚本之外的状态,因为这样做可能会导致应用出现不一致和 bug。
最好为状态和事件处理脚本 lambda 传递不可变值。此方法具有以下优势:
- 提升可重用性。
- 确保您的界面不会直接更改状态的值。
- 避免并发问题,因为您可确保不会从其他线程修改状态。
- 通常情况下,还可以降低代码的复杂性。
例如,接受 String
和 lambda 作为参数的可组合项可以从许多上下文中调用,并且可重用性较高。假设应用中的顶部应用栏始终显示文本并包含返回按钮。您可以定义一个更通用的 MyAppTopAppBar
可组合项,该可组合项用于接收文本和返回按钮句柄作为参数:
@Composable fun MyAppTopAppBar(topAppBarText: String, onBackPressed: () -> Unit) { TopAppBar( title = { Text( text = topAppBarText, textAlign = TextAlign.Center, modifier = Modifier .fillMaxSize() .wrapContentSize(Alignment.Center) ) }, navigationIcon = { IconButton(onClick = onBackPressed) { Icon( Icons.AutoMirrored.Filled.ArrowBack, contentDescription = localizedString ) } }, // ... ) }
ViewModel、状态和事件:示例
借助 ViewModel
和 mutableStateOf
,如果出现以下任一情况,您还可以在应用中引入单向数据流:
- 界面的状态通过
StateFlow
或LiveData
等可观察的状态容器公开。 ViewModel
处理来自应用界面或其他层的事件,并根据事件更新状态容器。
例如,在实现登录屏幕时,点按登录按钮应该会使应用显示一个进度旋转图标和网络调用。如果登录成功,您的应用会转到其他屏幕;如果发生错误,应用会显示信息提示控件。以下是如何为屏幕状态和事件建模的方法:
该屏幕有四种状态:
- 退出登录:当用户尚未登录时。
- 进行中:当您的应用目前正在尝试通过执行网络调用来让用户登录时。
- 错误:登录时出现错误。
- 登录成功:用户登录后。
您可以将这些状态建模为密封类。ViewModel
将状态公开为
一个 State
,设置初始状态,并根据需要更新状态。通过
ViewModel
还通过公开 onSignIn()
方法处理登录事件。
class MyViewModel : ViewModel() { private val _uiState = mutableStateOf<UiState>(UiState.SignedOut) val uiState: State<UiState> get() = _uiState // ... }
除了 mutableStateOf
API 之外,Compose 还提供 LiveData
、Flow
和 Observable
的扩展,用于注册为监听器,并将值表示为状态。
class MyViewModel : ViewModel() { private val _uiState = MutableLiveData<UiState>(UiState.SignedOut) val uiState: LiveData<UiState> get() = _uiState // ... } @Composable fun MyComposable(viewModel: MyViewModel) { val uiState = viewModel.uiState.observeAsState() // ... }
了解详情
如需详细了解 Jetpack Compose 中的架构,请参阅以下资源:
示例
您可以在一条文本字符串中支持多个链接,以便用户选择要前往的位置并提高互动度。 您可以设置文本的部分样式,以提高可读性、提升用户体验,并通过使用颜色和字体来激发更大的创造力。 您可以在用户在文本字段中输入内容(例如输入姓名、电子邮件地址、地址或其他联系信息)时验证输入内容。此验证可减少错误并为用户节省时间。 如需在应用中显示图片(用于内容和响应用户操作),请从磁盘或互联网上的外部来源加载图片。 卡片可为界面提供 Material Design 容器。 使用 TopAppBar 可组合项创建顶部应用栏,以帮助用户在应用中导航和访问功能。 了解如何使用 Compose Animation API 为状态值添加动画效果、使用转场效果添加动画效果、为可见性或大小更改添加动画效果,以及添加交叉淡化效果。 应用栏是位于屏幕顶部或底部的容器,其中包含主要功能和导航项。 您可以创建一个图标,以便根据用户的切换开关隐藏或显示密码,从而提高安全性并提升用户体验。 您可以加载可绘制文件来显示动画图片,从而在应用中打造更具互动性和吸引力的用户体验。动画图片非常适合用于创建加载指示器、成功或错误指示器,以及促进游戏开发和各种其他界面功能。 限制应用在小屏设备上的屏幕方向,但不限制其在大屏设备上的屏幕方向。 您可以在图片的剪裁区域周围绘制阴影,以便以剪辑的形状显示图片。 了解如何管理可拆卸键盘配置更改。 进度指示器会显示操作的状态。 创建分页列表,以便用户滚动浏览无法在一屏中显示的内容。水平分页列表可帮助用户浏览图片、幻灯片或商品轮播界面等内容。垂直分页列表非常适合内容丰富的应用,在这些应用中,用户可能需要滚动浏览大量内容(例如文章)。 您可以使用切换开关让用户选择两种状态之一。 为界面选择合适的组件,并了解如何在应用中实现该组件。 按钮可触发特定操作。 条状标签组件可直观地表示复杂的实体,通常包含图标和标签。 构建您的首个 Jetpack Compose 测试。了解如何使用 Compose 的测试工件编写界面测试、使用测试规则、查找器和断言。 用户可以通过悬浮操作按钮在应用中执行主要操作。 拒绝触控笔手掌误触。 对话框会在应用主要内容之上的层上显示弹出式消息或请求用户输入。 框架可将界面的不同部分(例如应用栏和悬浮操作按钮)整合在一起,从而让应用具有一致的外观和风格。支持在单个文本字符串中添加多个链接
设置文本的部分样式
在用户输入时验证输入内容
加载和显示图片
创建一个用作容器的卡片
显示顶部应用栏
Compose 中的动画
显示应用栏
根据用户切换开关显示或隐藏密码
显示动画图片
限制应用在手机上的屏幕方向,但不限制其在大屏设备上的屏幕方向
显示裁剪为某个形状的图片
管理可拆卸键盘配置变更
创建进度指示器
显示分页列表
添加用户可以切换的开关
显示互动组件
创建按钮
创建用于表示复杂实体的条状标签
在 Compose 中进行测试
创建悬浮操作按钮 (FAB)
拒绝触控笔手掌轻触
显示弹出式消息或请求用户输入
创建一个框架组件来将界面整合在一起
目前没有任何推荐文档页面。
请尝试登录您的 Google 账号。