Kotlin

时间:2017-05-23 18:57:07

标签: android kotlin

我在kotlin中为我的数据库实现实现了Room persistence lib。

以下是我的EntityDaoDatabase类:

Food.kt

@Entity
class Food(@ColumnInfo(name = "food_name") var foodName: String,
           @ColumnInfo(name = "food_desc") var foodDesc: String,
           @ColumnInfo(name = "protein") var protein: Double,
           @ColumnInfo(name = "carbs") var carbs: Double,
           @ColumnInfo(name = "fat") var fat: Double)
{
    @ColumnInfo(name = "id")
    @PrimaryKey(autoGenerate = true)
    var id: Long = 0
    @ColumnInfo(name = "calories")
    var calories: Double = 0.toDouble()
}

PersonalizedFood.kt

@Entity(primaryKeys = arrayOf("food_id","date"))
class PersonalizedFood(@ColumnInfo(name = "quantity") var quantity: Int,
                       @ColumnInfo(name = "unit") var unit: String,
                       @ColumnInfo(name = "date") var date: Date){

    @ColumnInfo(name = "food_id")
    var foodId:Long = 0
}

FoodDao.kt

@Dao
interface FoodDao {

    companion object{
        const val ID = "id"
        const val NAME = "name"
        const val PROTEIN = "protein"
        const val DESC = "desc"
        const val CARBS = "carbs"
        const val FAT = "fat"

        const val DATE = "date"
        const val FOOD_ID = "food_id"

        const val ALL_FOOD_LIST = "food"
        const val PERSONALISED_FOOD_LIST = "personalised_food"
    }

    /**
     * Returns food details of a food given by food_id
     */
    @Query("SELECT * FROM $ALL_FOOD_LIST WHERE $ID=:food_id")
    fun getFoodDetails(food_id:Long):Food

    /**
     * Inserts food items in all_food_list
     */
    @Insert
    fun addFoodList(list:ArrayList<Food>)

    @Insert(onConflict = REPLACE)
    fun saveFood(food:PersonalizedFood)

    @Query("SELECT * FROM $PERSONALISED_FOOD_LIST WHERE $FOOD_ID=:foodId and $DATE=:date")
    fun getFood(foodId:Int, data:Date):PersonalizedFood

    @Query("SELECT * FROM $ALL_FOOD_LIST where $ID in (select $FOOD_ID from $PERSONALISED_FOOD_LIST where $DATE = :date)")
    fun getFood(date:Date):ArrayList<Food>
}

Converter.kt

class Converter {

    companion object{
        @TypeConverter
        fun fromTimestamp(value: Long?): Date? {
            return if (value == null) null else Date(value)
        }

        @TypeConverter
        fun dateToTimestamp(date: Date): Long {
            return date.time
        }
    }
}

FoodDatabase.kt

@Database(entities = arrayOf(Food::class, PersonalizedFood::class), version = 1)
@TypeConverters(Converter::class)
abstract class FoodDatabase : RoomDatabase(){
    abstract fun foodDao():FoodDao

    companion object{
        private val databaseName = "diet"

        var dbInstance:FoodDao? = null
        fun getInstance(context:Context):FoodDao?{
            if(dbInstance == null)
                dbInstance = Room.inMemoryDatabaseBuilder(context, FoodDatabase::class.java).build().foodDao()
            return dbInstance;
        }
    }
}

当我运行以下代码来创建数据库时:

FoodDatabase.getInstance(baseContext)?.getFood(Calendar.getInstance().time)

它给了我以下例外:

  

造成:java.lang.RuntimeException:无法找到实现   com.chandilsachin.diettracker.database.FoodDatabase。 FoodDatabase_Impl   不存在                                                                                          在   android.arch.persistence.room.Room.getGeneratedImplementation(Room.java:90)                                                                                          在   android.arch.persistence.room.RoomDatabase $ Builder.build(RoomDatabase.java:340)                                                                                          在   com.chandilsachin.diettracker.database.FoodDatabase $ Companion.getInstance(FoodDatabase.kt:21)                                                                                          在   com.chandilsachin.diettracker.MainActivity $ SetUpFoodDatabase.doInBackground(MainActivity.kt:95)                                                                                          在   com.chandilsachin.diettracker.MainActivity $ SetUpFoodDatabase.doInBackground(MainActivity.kt:77)                                                                                          在android.os.AsyncTask $ 2.call(AsyncTask.java:295)                                                                                          在java.util.concurrent.FutureTask.run(FutureTask.java:237)                                                                                          在android.os.AsyncTask $ SerialExecutor $ 1.run(AsyncTask.java:234)                                                                                          在   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)                                                                                          在   java.util.concurrent.ThreadPoolExecutor中的$ Worker.run(ThreadPoolExecutor.java:588)                                                                                          在java.lang.Thread.run(Thread.java:818)

有没有人在kotlin中实施过房间持久性?

被修改 此问题被标记为this的重复。虽然问题陈述是相同的,但解决方案并没有解决我的问题。解决方案说我必须将替换annotationProcessor添加到kapt "android.arch.persistence.room:compiler:1.0.0-alpha1"依赖项。我做了这些更改,但在项目构建时导致了gradle错误。

  

信息:Gradle任务[:app:assembleDebug]警告:警告:   来自注释处理器的支持的源版本“RELEASE_7”   'android.arch.persistence.room.RoomProcessor'小于-source'1.8'   警告:警告:任何人都无法识别以下选项   处理器:'[kapt.kotlin.generated]'   /Users/BBI-M1025/Documents/BBI/Workspace_fun/Android/diet-tracker/app/src/main/java/com/chandilsachin/diettracker/database/Food.kt       错误:(1,1)处理注释时发生了一些错误。请参阅上面的错误消息。       错误:任务':app:kaptDebugKotlin'执行失败。

     
    

编译错误。有关详细信息,请参阅日志         信息:10年内建筑失败         信息:2个错误         信息:2个警告         信息:请参阅控制台中的完整输出

  

我还附上了我的gradle文件:

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

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.chandilsachin.diettracker"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    compile 'com.android.support:appcompat-v7:25.0.1'
    compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha8'
    compile 'com.android.support:cardview-v7:25.0.1'
    compile 'com.android.support:recyclerview-v7:25.0.1'
    compile 'com.github.ne1c:rainbowmvp:1.2.1'
    compile "org.jetbrains.anko:anko-commons:0.10.0"

    /*annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha1"
    compile "android.arch.lifecycle:extensions:1.0.0-alpha1"
    annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha1"*/

    compile "android.arch.persistence.room:runtime:1.0.0-alpha1"
    annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha1"
    kapt "android.arch.persistence.room:compiler:1.0.0-alpha1"

    testCompile 'junit:junit:4.12'
}
repositories {
    mavenCentral()
}

有没有人遇到过这个问题?

5 个答案:

答案 0 :(得分:22)

在遇到这个问题后我的头转了一会儿,我找到了解决方案。

这真的很难,因为目前还没有官方教程,博客等帮助解决这个问题。

我必须为gradle插件和依赖项的所有组合做几次点击和试用,因为我知道gradle配置只有一些问题。

让我们来解决方案:

我不得不从build.gradle(:module)文件中删除apply plugin: 'kotlin-kapt' 并将annotationProcessor "android.arch.persistence.room:compiler:1.0.0-alpha1"替换为kapt "android.arch.persistence.room:compiler:1.0.0-alpha1"

这是成功编译代码的gradle配置。

但还有更多要检查的事情。与Room Persistence lib doc中给出的java不同,您必须初始化@Entity class的属性。虽然有getter setter但是没有提到创建一个带初始化的构造函数。 所以我不得不改变我的@Entity课程:

@Entity(tableName = "all_food_list")
class Food (@ColumnInfo(name = "food_name") var foodName: String = "",
            @ColumnInfo(name = "food_desc") var foodDesc: String = "",
            @ColumnInfo(name = "protein") var protein: Double = 0.0,
            @ColumnInfo(name = "carbs") var carbs: Double = 0.0,
            @ColumnInfo(name = "fat") var fat: Double = 0.0,
            @ColumnInfo(name = "calories") var calories: Double = 0.0)
{
    @ColumnInfo(name = "id")
    @PrimaryKey(autoGenerate = true)
    var id: Long = 0
}

现在对于TypeConverts,与java不同,你需要创建普通函数而不是静态函数(伴随对象):

class Converters{

        @TypeConverter
        fun fromTimestamp(value: String): Calendar {
            val arr = value.split("-")
            val cal = Calendar.getInstance()
            cal.set(arr[0].toInt(), arr[1].toInt(), arr[2].toInt())
            return cal
        }

        @TypeConverter
        fun dateToTimestamp(date: Calendar): String {
            return "${date.get(Calendar.DATE)}-${date.get(Calendar.MONTH)+1}-${date.get(Calendar.YEAR)}"
        }

}

我还要添加build.gradle文件以使其更清晰:

<强>的build.gradle(:项目)

buildscript {
    ext.kotlin_version = '1.1.2-4'
    ext.gradle_version_stable = '2.3.2'
    ext.gradle_version_preview = '3.0.0-alpha1'
    ext.anko_version = '0.10.0'
    repositories {
        maven { url 'https://maven.google.com' }
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.0.0-alpha1'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        maven { url 'https://maven.google.com' }
        jcenter()
        maven { url "https://jitpack.io" }
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

<强>的build.gradle(:模块)

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

android {
    compileSdkVersion 25
    buildToolsVersion "25.0.2"
    defaultConfig {
        applicationId "com.chandilsachin.diettracker"
        minSdkVersion 16
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}


dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    ...
    ...
    // room persistence dependency 
    compile "android.arch.persistence.room:runtime:1.0.0-alpha1"
    kapt "android.arch.persistence.room:compiler:1.0.0-alpha1"

    testCompile 'junit:junit:4.12'
}
repositories {
    mavenCentral()
}

我认为这就是全部,我做了我的代码工作。

希望这也有助于其他人。

答案 1 :(得分:1)

这是我的gradle文件,我不需要添加插件。

<强>的build.gradle(项目):

buildscript {
    ext.kotlin_version = '1.1.2-4'
    ext.lifecycle_version = '1.0.0-alpha1'
    ext.room_version = '1.0.0-alpha1'

    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.2'
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"

    }
}

build.gradle(app)

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

//enable anotation processing with kotlin, disabled by default
kapt {
    generateStubs = true
}


android {
/**
...
**/
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])

    //kotlin
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"

    //support
    compile 'com.android.support:appcompat-v7:25.3.1'

    //google architecture
    compile "android.arch.lifecycle:runtime:$lifecycle_version"
    compile "android.arch.lifecycle:extensions:$lifecycle_version"
    annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
    kapt "android.arch.lifecycle:compiler:$lifecycle_version"

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

}
repositories {
    mavenCentral()
}

然后运行menu build-&gt; make project来创建impl类。 希望这有帮助

答案 2 :(得分:0)

我做了一个类似的使用Java的例子,以前有同样的问题和解决方案是添加APT线apt“android.arch.persistence.room:compiler:1.0.0-alpha1”

不申请:申请插件:'kotlin-kapt'。删除这一行!!

您必须清除项目并重新运行才能再次运行,并尝试在手机或虚拟设备上卸载现有应用。 希望你能帮忙。

答案 3 :(得分:0)

当我尝试从Java迁移到Kotlin时,我遇到了同样的问题:

RuntimeException: cannot find implementation for AppDatabase. AppDatabase_Impl does not exist

我在这个问题中尝试了所有这些答案,但都没有用,然后我找到了一篇文章:Kotlinlang Tutorials - Android Frameworks Using Annotation Processing

  

在Kotlin中,您可以使用Kotlin注释处理工具(kapt)而不是注解处理器,以类似于Java的方式指定依赖项。

然后我通过将所有annotationProcessor更改为kapt来修改build.gradle(Module:app),它可以正常工作:

--- a/app/build.gradle
+++ b/app/build.gradle
@@ -2,6 +2,8 @@ apply plugin: 'com.android.application'

 apply plugin: 'kotlin-android'
+apply plugin: 'kotlin-kapt'
 apply plugin: 'kotlin-android-extensions'

 android {
     // Butter Knife
     implementation "com.jakewharton:butterknife:$butterknife_version"
-    annotationProcessor "com.jakewharton:butterknife-compiler:$butterknife_version"
+    kapt "com.jakewharton:butterknife-compiler:$butterknife_version"

     // Room
     implementation "android.arch.persistence.room:runtime:$arch_lifecycle_version"
-    annotationProcessor "android.arch.persistence.room:compiler:$arch_lifecycle_version"
+    kapt "android.arch.persistence.room:compiler:$arch_lifecycle_version"
     // LifeCycle
     implementation "android.arch.lifecycle:runtime:$arch_lifecycle_version"
     implementation "android.arch.lifecycle:extensions:$arch_lifecycle_version"
     implementation "android.arch.lifecycle:common-java8:$arch_lifecycle_version"
-    annotationProcessor "android.arch.lifecycle:compiler:$arch_lifecycle_version"
+    kapt "android.arch.lifecycle:compiler:$arch_lifecycle_version"

     // Dagger
     implementation "com.google.dagger:dagger:$dagger_version"
     implementation "com.google.dagger:dagger-android-support:$dagger_version"
-    annotationProcessor "com.google.dagger:dagger-compiler:$dagger_version"
-    annotationProcessor "com.google.dagger:dagger-android-processor:$dagger_version"
+    kapt "com.google.dagger:dagger-compiler:$dagger_version"
+    kapt "com.google.dagger:dagger-android-processor:$dagger_version"
}

如果使用黄油刀,还应该更改为kapt,否则注入的视图可能为空。

答案 4 :(得分:0)

在Dao界面中,检查诸如@Query ..之类的注释是从会议室数据库类而非其他地方导入的