在AndroidManifest,用了room之后,我们可以看到这个:
plugins {
id("kotlin-kapt")
}
在这篇文章我就来详细介绍一下这个插件。写在最前面,目前google已经推出了ksp,可以取代kapt,这个也更好更快,大家可以重构的时候用这个,在这我只专门介绍kapt
前置知识
- 注解 (Annotation): 只是代码里的“标签”,本身没有逻辑。
- 注解处理器 (APT): 是一段在编译期运行的代码,它专门扫描这些标签。
- Java 的局限: Java 原生就有 APT(Annotation Processing Tool)。但 Kotlin 的语法和 Java 不同,Java 的编译器看不懂 Kotlin 代码,因为Java 注解处理器(APT)是基于 Java 抽象语法树(AST) 工作的。
编译器生成代码
我写了一个简单的类,但我希望编译器能帮我自动生成一堆枯燥的模版代码。尤其是在数据库方面,对于 Android 的 Room 框架来说,只需要写一个接口(DAO):
@Dao
interface UserDao {
@Query("SELECT * FROM user")
fun getAll(): List<User>
}
本质问题是: 接口是不能运行的。在编译时,必须有某个“东西”读取这个 @Dao 注解,然后生成一个真正的 UserDao_Impl 类,里面写满了复杂的 SQL 执行逻辑。
所以为了解决这些问题,kapt应运而生,所以在这里我们就可以理解kapt其实就一个编译器插件,添加room的时候一定要配它,那么问题又来了,为什么是room要配它呢?
Room的编译时安全
- 验证 SQL: 当你写下
@Query("SELECT * FROM users")时,如果你把表名写错了,Room 必须在编译阶段就报错,而不是等用户运行 App 崩溃时才发现。 - 生成实现类: 正如前面提到的,Room 需要通过注解处理器生成大量的
_Impl代码来处理数据库连接、游标(Cursor)转换等底层操作。
那么我们可以看到room其实用了很多注解,但这其实只是一个注解,像我前面所说的它只是代码里的“标签”,本身没有逻辑。所以我们需要一个让 Room 的注解处理器(本质是一个 Java 程序) 能够跨语言读取到 Kotlin 源码里的元数据(Metadata)。