使用 Compose + ViewModel + Flow 进行 GUI 编程

课题

  1. 程序界面由3个文本编辑框和1个文本标签组成。
  2. 要求文本标签实时显示3个文本编辑框所输入的数字之和。
  3. 文本编辑框输入的不是合法数字时,将其值视为0。
  4. 3个文本编辑框的初值分别为1,2,3。

创建工程

打开 Android Studio,File / New / Project...
在 New Project 向导的第1页,选择 Empty Compose Activity
在向导的第2页 Name 填上 Compose Example
在向导的第4页点击 Finish 按钮创建工程

ViewModel

在 com.example.composeexample 包中添加 NumbersViewModel 类

class NumbersViewModel : ViewModel() {     val number1 = MutableStateFlow(1)     val number2 = MutableStateFlow(2)     val number3 = MutableStateFlow(3)     val result = combine(number1, number2, number3) { n1, n2, n3 ->         ((n1.toIntOrNull() ?: 0) + (n2.toIntOrNull() ?: 0) + (n3.toIntOrNull() ?: 0)).toString()     } } 

配置 UI

打开 MainActivity.kt,将内容修改为

class MainActivity : ComponentActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContent {             ComposeExampleTheme {                 // A surface container using the 'background' color from the theme                 Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {                     AddNumbers()                 }             }         }     } }  @Composable fun LeftText(     text: String = , ) {     Text(         text = text,         modifier = Modifier.width(40.dp),         textAlign = TextAlign.Center,     ) }  @Composable fun RightTextField(     value: String,     onValueChange: (String) -> Unit,     readOnly: Boolean = false, ) {     TextField(         value = value,         onValueChange = onValueChange,         readOnly = readOnly,         modifier = Modifier.width(200.dp),         textStyle = LocalTextStyle.current.copy(textAlign = TextAlign.End)     ) }  @Composable fun AddNumbers(vm: NumbersViewModel = NumbersViewModel()) {     Column(         modifier = Modifier.fillMaxSize(),         horizontalAlignment = Alignment.CenterHorizontally,         verticalArrangement = Arrangement.Center     ) {         Row {             LeftText()             RightTextField(                 value = vm.number1.collectAsState().value,                 onValueChange = { vm.number1.value = it },             )         }         Row {             LeftText()             RightTextField(                 value = vm.number2.collectAsState().value,                 onValueChange = { vm.number2.value = it }             )         }         Row(verticalAlignment = Alignment.CenterVertically) {             LeftText(+)             RightTextField(                 value = vm.number3.collectAsState().value,                 onValueChange = { vm.number3.value = it }             )         }         Row {             LeftText()             RightTextField(                 value = vm.result.collectAsState().value,                 onValueChange = {},                 readOnly = true             )         }     } }  @Preview(showBackground = true) @Composable fun DefaultPreview() {     ComposeExampleTheme {         AddNumbers()     } }