Android Room持久化库和Kotlin

58
我将尝试使用Kotlin和Room Persistence Library编写一个简单的应用程序。 我按照Android Persistence codelab中的教程进行操作。
这是我的Kotlin AppDatabase类:
@Database(entities = arrayOf(User::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userModel(): UserDao

    companion object {
        private var INSTANCE: AppDatabase? = null
        @JvmStatic fun getInMemoryDatabase(context: Context): AppDatabase {
            if (INSTANCE == null) {
                INSTANCE = Room.inMemoryDatabaseBuilder(context.applicationContext, AppDatabase::class.java).allowMainThreadQueries().build()
            }
            return INSTANCE!!
        }

        @JvmStatic fun destroyInstance() {
            INSTANCE = null
        }
    }
}

但当我尝试运行应用时,它立即崩溃了。 以下是崩溃日志:

Caused by: java.lang.RuntimeException: cannot find implementation for com.ttp.kotlin.kotlinsample.room.AppDatabase. AppDatabase_Impl does not exist
    at android.arch.persistence.room.Room.getGeneratedImplementation(Room.java:90)
    at android.arch.persistence.room.RoomDatabase$Builder.build(RoomDatabase.java:340)
    at com.ttp.kotlin.kotlinsample.room.AppDatabase$Companion.getInMemoryDatabase(AppDatabase.kt:19)
    at com.ttp.kotlin.kotlinsample.MainKotlinActivity.onCreate(MainKotlinActivity.kt:28)
    at android.app.Activity.performCreate(Activity.java:6272)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2387)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2494) 
    at android.app.ActivityThread.access$900(ActivityThread.java:157) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1356)

看起来类 AppDatabase_Impl 没有自动生成。 我检查了从codelab下载的原始java应用程序,并发现 AppDatabase_Impl 是自动生成的。 Kotlin版本:1.1.2-3 Room版本:1.0.0-alpha1 有经验的人吗? 编辑: 使用解决了我的问题。 在我的情况下,我必须用替换。

2
你能同时发布你的 build.gradle 文件吗? - Christian Brüggemann
11
你的模块的 build.gradle 中有没有 apply plugin: 'kotlin-kapt'kapt "android.arch.persistence.room:compiler:1.0.0-alpha1" 这两行代码? - Vyacheslav Gerasimov
1
谢谢。使用kapt插件解决了我的问题。 - Thanh Pham
@ThanhPham 我也遇到了同样的问题,但是添加kapt会引入一些gradle错误,请看这里 https://dev59.com/hOk5XIcBkEYKwwoY_Ox3。你能提供你的gradle文件吗? - Sachin Chandil
@chandil03 我看到你刚刚添加了 kapt。在我的情况下,我必须用 kapt 替换 annotationProcessor。 - Thanh Pham
6个回答

53

通常在项目的build.gradle文件中,我会定义依赖项的版本:

ext {
    buildToolsVersion = '25.0.2'
    supportLibVersion = '25.3.1'
    espressoVersion = '2.2.2'
    archRoomVersion = '1.0.0-alpha1'
}

因此,在应用程序的build.gradle文件中,依赖项看起来像:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"

    compile "com.android.support:appcompat-v7:${rootProject.supportLibVersion}"

    compile "android.arch.persistence.room:runtime:${rootProject.archRoomVersion}"
    annotationProcessor "android.arch.persistence.room:compiler:${rootProject.archRoomVersion}"
    kapt "android.arch.persistence.room:compiler:${rootProject.archRoomVersion}"

    androidTestCompile("com.android.support.test.espresso:espresso-core:${rootProject.espressoVersion}", {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    testCompile 'junit:junit:4.12'
}
现在您可以使用 Kotlin 定义实体 Dao 和数据库。
数据库:
@Database(entities = arrayOf(User::class), version = 1)
abstract class Database : RoomDatabase() {
    abstract fun userDao(): UserDao
}

实体:

@Entity(tableName = "user")
class User {
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0
    var name: String = ""
}

道:

@Dao
interface UserDao {
    @Query("SELECT * FROM user")
    fun getAll(): List<User>

    @Insert
    fun insertAll(vararg users: User)

    @Delete
    fun delete(user: User)
}

NB:带有参数的查询。 Kotlin修改了参数名称,因此检索属于特定用户userId的所有电子邮件的SQL查询为:

@Query("SELECT * FROM email "
            + "INNER JOIN user ON user.id = email.userId "
            + "WHERE user.id = :arg0")
    fun getEmailsForUser(userId: Int): List<Email>

1
感谢您的帮助。在我的情况下,Kotlin将参数重命名为p0、p1...而不是arg0、arg1... - Thanh Pham
@Nicola De Fiorenze 我也遇到了同样的问题,但是添加kapt会引入一些gradle错误,请看这里https://dev59.com/hOk5XIcBkEYKwwoY_Ox3。 - Sachin Chandil
我该如何调用 db.userDao().insertAll(user) - Hasan A Yousef
2
此外,根据另一个答案提到的,apply plugin: 'kotlin-kapt'build.gradle 文件中也是必需的。 - shelll

39

在我的情况下,在 build.gradle 中,当你有 "annotationProcessor" 时,你需要使用 "kapt" 进行复制,这样就可以正常工作。

compile "android.arch.persistence.room:runtime:$room_version"
annotationProcessor "android.arch.persistence.room:compiler:$room_version"
kapt "android.arch.persistence.room:compiler:$room_version"

谢谢你的帮助。 - Thanh Pham
@Lyofen 我遇到了同样的问题,但是添加kapt会引发一些Gradle错误,请在这里查看 https://dev59.com/hOk5XIcBkEYKwwoY_Ox3。 - Sachin Chandil
非常感谢您,先生! - Moti Bartov

12

请尝试以下步骤

步骤1:project.gradle文件中设置room_version

buildscript {
    ext.kotlin_version = '1.1.51'
    ext.room_version = '1.0.0-alpha9-1'
...

步骤 2.app.gradle 文件中应用 kotlin-kapt 插件,这解决了我的问题。

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
...

第三步。app.gradle 文件中添加 kapt 依赖项

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation "android.arch.persistence.room:runtime:$room_version"
    annotationProcessor "android.arch.persistence.room:compiler:$room_version"
    kapt "android.arch.persistence.room:compiler:$room_version"
...
}

4

1
我差点放弃了。但是在按照dharmin007所说的做后,我还必须要清理项目。这样才能使它工作。我注意到每当你将kapt添加到gradle中后,必须在同步gradle后清理项目。

0
我不知道我的回答是否有必要,我知道一些之前的回答已经包括了这个但他们添加了其他的东西。
只需添加 apply plugin: 'kotlin-kapt'

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接