别再让团队困惑:少有人提及的 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 回调是"承诺",意图是"事实"。

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

相关推荐
alexhilton1 天前
使用Android Archive进行打包
android·kotlin·android jetpack
Junerver4 天前
我写了一个 Compose Multiplatform 组件库,你可能会用到
kotlin·android jetpack
我命由我123455 天前
Jetpack Room - Room 查询返回列表无需判空、LIKE 关键字
android·java·开发语言·java-ee·android jetpack·android-studio·android runtime
QING6186 天前
Kotlin 日常开发常用语法糖整理 —— 速记
android·kotlin·android jetpack
我命由我123456 天前
Android 开发问题:EditText 控件的 android:imeOptions=“actionDone“ 属性不生效
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
我命由我123456 天前
Android 开发问题:获取到的 Android ID 发生了变化
android·java·开发语言·java-ee·android studio·android jetpack·android runtime
我命由我123456 天前
Android 开发问题:Unable to find explicit activity class
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
我命由我123456 天前
Android 开发问题:全局的主题颜色设置,导致 CheckBox 控件在勾选状态下不显示样式
android·java·开发语言·java-ee·intellij-idea·intellij idea·android jetpack
alexhilton9 天前
Android的Agent优先时代:构建时vs运行时
android·kotlin·android jetpack
我命由我123459 天前
Android 开发问题:View 的 getWidth、getHeight 方法返回的值都为 0
android·java·java-ee·android studio·android jetpack·android-studio·android runtime