Android使用MCP把Kotlin扩展迁移至ViewBinding

前言

kotlinx.android.synthetic 已在 Kotlin 1.8+ 彻底移除,老项目必须迁移到 ViewBinding

手动改几百个 Activity / Fragment 成本很高,且容易漏掉 include、代码里 inflate 的子布局、SeekBar.max 等细节。

本文记录我在项目中实际使用的 MCP Server + Cursor Rule 配置,让 AI 按统一规范批量完成迁移。

MCP 包地址:z-mcp-vb-migration - npm

整体思路

1
2
3
4
5
Cursor Agent

├── MCP: vb_list_kt_files → 扫描待迁移文件
├── MCP: vb_migrate_kt_file → 单文件自动迁移 + 预览
└── Rule: vb-migration.mdc → 迁移后 Adapter 等补充修正
  • MCP 负责机械替换:删 synthetic import、改基类、替换控件引用、补 include 的 android:id
  • Rule 负责 MCP 覆盖不到的项目特有坑(如 BRVAH 的 adapter?.data = list

MCP 配置

在项目根目录创建 .cursor/mcp.json

1
2
3
4
5
6
7
8
{
"mcpServers": {
"z-mcp-vb-migration": {
"command": "npx",
"args": ["-y", "z-mcp-vb-migration", "--stdio", "--android-module=app"]
}
}
}

说明:

参数 含义
npx -y z-mcp-vb-migration 免安装拉取 npm 包,当前版本 1.0.3
--stdio 以 MCP 标准输入输出模式运行(Cursor 必需)
--android-module=app 指定 Android 模块名,扫描 app/src/main 下的 Kotlin 与 layout

配置好后,在 Cursor Settings → MCP 中确认 z-mcp-vb-migration 状态为绿色(ready),Agent 即可调用其工具。

Cursor Rule 配置

MCP 做完主布局替换后,还需处理项目特有的 Adapter 写法。在 .cursor/rules/vb-migration.mdc 中补充:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
---
description: ViewBinding 迁移时的 Kotlin/Adapter 注意事项
globs: app/src/main/java/**/*.kt
alwaysApply: false
---

# ViewBinding 迁移补充规范

迁移 synthetic 到 ViewBinding 后,检查并修正 Adapter 数据赋值写法。

## 禁止:`adapter?.data = list`

Kotlin 不支持对可空调用左侧赋值,会报错 `Unsupported safe call on assignment target`。

## `setNewInstance` vs `setList`(BRVAH 3.0.4)

| 方法 | 行为 | 适用场景 |
|------|------|----------|
| `setNewInstance(list)` | 替换 adapter 内部 data 的**内存引用** | Activity 持有 `mDatas`,后续 `mDatas.add()` 再 `notifyDataSetChanged()` |
| `setList(list)` | **不清引用**,清空后把内容 copy 进 adapter.data | 接口返回完整新列表,一次性替换展示数据 |

BRVAH 官方注释:*「通常情况下,如非必要,请使用 setList」*——指一般刷新场景;但若 adapter 与页面**共享同一个 MutableList 引用**,必须用 `setNewInstance`,否则 `setList` 只 copy 当时的内容,后续对原 list 的 add 不会反映到 adapter。

// ❌ 错误
resourceCommonAdapter?.data = mDatas

// ✅ 共享 mDatas 引用,后续 loadData() 里 add(本项目常见写法)
resourceCommonAdapter?.setNewInstance(mDatas)

// ✅ 接口返回新数据,一次性替换
adapter?.setList(apiList)

// ✅ 已确保非空
resourceCommonAdapter.setNewInstance(mDatas)

## 迁移后检查项

- 搜索 `?.data =` 并替换为 `?.setNewInstance(...)` 或 `?.setList(...)`
- 判断页面是「共享 list 引用」还是「一次性赋值」,选对方法

Rule 要点:

  • globs: app/src/main/java/**/*.kt:只在编辑 Kotlin 源码时生效
  • alwaysApply: false:按需触发,不污染无关对话
  • 解决 MCP 自动替换后常见的 adapter?.data = mDatas 编译错误

迁移工作流

在 Cursor Agent 中按以下步骤操作:

1. 扫描待迁移文件

1
请调用 vb_list_kt_files,列出所有仍使用 synthetic 的 Kotlin 文件

2. 逐文件迁移

1
请用 vb_migrate_kt_file 迁移 xxx/yyy/SomeActivity.kt,并根据 preview 核对后写盘

建议按模块分批(如先 kongjian、再 jiaoyan),每批 5~10 个文件。

3. 人工处理标记项

MCP 不会自动迁移的场景,需按 ViewBinding 迁移注意项 手动处理:

  • hasCodeLayouts: true:代码里 inflate(R.layout.item_xxx) 的子布局,改用 ItemXxxBinding
  • primaryLayoutCount > 1:多个主布局 import,确认保留哪一个
  • 同名 id 与局部变量(如 list 既是 RecyclerView 又是 MutableList
  • SeekBar.max / ProgressBar.max 属性赋值

4. Rule 补充检查

迁移写盘后,Agent 按 vb-migration.mdc 检查:

1
2
3
# 搜索残留问题
rg "\?\.data\s*=" app/src/main/java
rg "kotlinx\.android\.synthetic" app/src/main/java

5. 批量编译验证

1
./gradlew :app:compileGuanchengDebugKotlin

全部迁完且编译通过后,再在 build.gradle 中移除 kotlin-android-extensions 插件。

迁移效果示例

KjMp3Activity 为例,迁移前:

1
2
3
4
5
6
7
8
9
10
import kotlinx.android.synthetic.main.activity_kjmp3.*

class KjMp3Activity : BaseMvpActivity<KjResourcePresenter>(), ... {
override fun getContentView(): Int = R.layout.activity_kjmp3

override fun initView() {
zy_title.setTxtBold()
zy_title.text = resourceBean.resourcename
}
}

迁移后:

1
2
3
4
5
6
7
8
9
import com.xhkjedu.schoolteacher.databinding.ActivityKjmp3Binding

class KjMp3Activity : BaseMvpActivityVB<KjResourcePresenter, ActivityKjmp3Binding>(), ... {

override fun initView() {
binding.zyTitle.setTxtBold()
binding.zyTitle.text = resourceBean.resourcename
}
}

目录结构一览

1
2
3
4
5
6
7
schoolteacherandroid/
├── .cursor/
│ ├── mcp.json # MCP Server 配置
│ └── rules/
│ └── vb-migration.mdc # 迁移补充规范
└── app/
└── src/main/java/... # 待迁移 / 已迁移的 Kotlin 文件

注意事项

  1. 先开启 ViewBindingbuild.gradlebuildFeatures { viewBinding true },并准备好 BaseMvpActivityVB 等基类(见 ViewBinding 基类封装
  2. MCP 迁主布局,人迁子布局:列表 item、弹窗、ViewPager 页等代码 inflate 的布局,MCP 只标记不自动改
  3. Rule 补业务坑:BRVAH Adapter、项目自定义写法等,靠 Rule 约束 Agent 迁移后自检
  4. 不要逐文件全量构建:按 MCP 返回的 workflowHints,批量迁完再 compileDebugKotlin