别再让团队困惑:少有人提及的 MVI 命名规范

为什么你的 MVI 页面代码读起来比本该有的难度更高------以及一个简单的解决办法

如果你从 MVVM 迁移到了 MVI,大概率遇到过这种情况:团队盯着复杂页面的代码,绞尽脑汁也理不清流程。架构本身"没问题",但总感觉哪里不对劲。

问题根源何在?糟糕的命名规范------具体来说,是把 UI 回调和 MVI 意图(Intent)混为一谈。

让我具体说明。

MVVM 遗留习惯

在 MVVM 中,我们不会过多思考 UI 触发操作该如何转化为行为,只是直接调用 ViewModel 的方法:

c 复制代码
// MVVM - 简单直接
Button(onClick = { viewModel.login() })

TextField(onValueChange = { viewModel.updateEmail(it) })

这种方式有效且直观,但当切换到 MVI 时,这个习惯就会引发问题。

MVI 的不同之处

MVI 构建的核心是 语义清晰性 。每一个意图(Intent)都代表某件已经发生的事,是一个在单向数据流管道中传递的事件。架构本身就承载着明确的语义。

如果你模糊了"监听某件事"和"某件事已发生"的界限,就会破坏这种清晰性。

两种场景,两种规范

这个思维模型能拯救你的代码库:

1. UI 回调 → 现在时 + "On" 前缀

这些是触发器,你正在为未来可能发生的事件注册监听器。

c 复制代码
// ✅ 正确示例 - 监听触发事件
Button(onClick = { onLoginClick() })
TextField(onValueChange = { onEmailChange(it) })

可以这样理解:"当这件事发生时,执行对应的操作。"

这里用 Clicked 是错误的,因为事件尚未发生,你只是在设置监听器。

2. MVI 意图(Intent)→ 过去分词

这些是已经发生的事件,现在要发送到你的状态处理器(reducer/ViewModel) 中。

c 复制代码
// ✅ 正确示例 - 事件已发生
sealed interface LoginIntent {
    data object LoginButtonClicked : LoginIntent
    data class EmailChanged(val value: String) : LoginIntent
    data class PasswordChanged(val value: String) : LoginIntent
    data object ForgotPasswordTapped : LoginIntent
}

可以这样理解:"这件事已经发生了,需要处理。"

这里用 OnLoginClick 是多余的,因为意图(Intent)本身就定义为"已发生的事件"。

完整示例

规范的 MVI 代码应该是这样的:

c 复制代码
@Composable
fun LoginScreen(
    state: LoginState,
    onIntent: (LoginIntent) -> Unit
) {
    TextField(
        value = state.email,
        onValueChange = { onIntent(EmailChanged(it)) }  // 回调 → 意图
    )
    
    Button(
        onClick = { onIntent(LoginButtonClicked) }  // 回调 → 意图
    ) {
        Text("Login")
    }
}

注意其中的转化逻辑:

  • **onValueChange**(现在时,触发器)→ **EmailChanged**(过去时,事件)
  • **onClick**(现在时,触发器)→ **LoginButtonClicked**(过去时,事件)

MVVM 到 MVI 的思维转变

维度 MVVM MVI
UI 触发方式 直接调用方法 发送意图(Intent)
命名核心 要执行什么操作 发生了什么事
流程方向 双向感知 单向、显式
语义权重

在 MVVM 中,viewModel.login() 是一条"指令";而在 MVI 中,LoginButtonClicked 是一个"事实"。

为什么这很重要

当你的团队阅读遵循规范命名的 MVI 代码时:

  • 意图自文档化:能清晰知道每个状态变化的触发源
  • 调试更简单:日志读起来像"故事线":"EmailChanged → PasswordChanged → LoginButtonClicked → LoginFailed"
  • 新人上手更快:无需额外文档就能理解流程

速查指南

场景 命名规范 示例
UI 回调 on + 现在时 onClickonTextChange
MVI 意图 过去分词 ClickedChangedSelected

核心结论

MVI 的优势在于其显式性。不要因为沿用 MVVM 的不良命名习惯,而削弱它的优势。

UI 回调是"承诺",意图是"事实"。

按照这个原则命名,你会发现复杂页面的代码重新变得清晰易读。

相关推荐
alexhilton3 天前
千万别误用Android Skills
android·kotlin·android jetpack
XiaoLeisj5 天前
Kotlin Flow 常用操作符:数据变换 map、filter、onEach,时间控制 debounce、sample,终端聚合 reduce、fold
android·kotlin·android jetpack·协程·响应式编程·flow
XiaoLeisj6 天前
Kotlin Flow:冷流收集、并行订阅、emit 推送、delay 延迟、collect 全量收集与 collectLatest 的实时数据处理
android·kotlin·android jetpack·协程·flow
我命由我123457 天前
Jetpack Compose - @Preview 注解
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
学习使我健康9 天前
一个基于 **Jetpack Compose + Material 3** 的 Android 入门示例项目,演示 Compose 声明式 UI 的核心用法
ui·kotlin·android jetpack
alexhilton10 天前
Android XR 开发入门完全指南
android·kotlin·android jetpack
我命由我1234512 天前
Jetpack Compose - Material Design 断点范围、WindowSizeClass、针对不同屏幕尺寸创建预览、四类导航栏
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime
我命由我1234512 天前
Jetpack Compose - MaterialExpressiveTheme 与 MaterialTheme、ColorScheme
android·java·开发语言·java-ee·kotlin·android jetpack·android runtime
我命由我1234513 天前
Kotlin 面向对象 - Kotlin 类变量与类方法
java·服务器·后端·java-ee·kotlin·android jetpack·android runtime
小孔龙15 天前
Compose 布局与绘制:LayoutNode、DisplayList 与 GraphicsLayer
android·android jetpack