Search code examples
androidkotlinandroid-room

java.lang.RuntimeException: cannot find implementation for com.example.laptopsdb.AppDatabase. AppDatabase_Impl does not exist (July 2022)


Yes I have already tried some old guides, I described it below.

I created new project for Room Database in Kotlin Android. I followed the official google documentation for it.

https://developer.android.com/training/data-storage/room

If I follow as per documentation I get error

java.lang.RuntimeException: cannot find implementation for com.example.laptopsdb.AppDatabase. AppDatabase_Impl does not exist

I also tried changing room-runtime to room-ktx but the error is same. Moreover, I tried adding id 'kotlin-kapt' and changing annotationProcessor to kapt but that give me following error, errors actually, bunch of them, while auto opening UserDao.java file

https://github.com/subjectOneThree/StackOverFLowShares/blob/main/Screenshot_20220715_215040.png

My code is almost stock according to documentation, however you can checkout if I made any stupid mistake

build.gradle (app)

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'

    //id 'kotlin-kapt'
}

android {
    compileSdk 32

    defaultConfig {
        applicationId "com.example.laptopsdb"
        minSdk 21
        targetSdk 32
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {

    apply plugin: "kotlin-kapt"

    implementation 'androidx.core:core-ktx:1.7.0'
    implementation 'androidx.appcompat:appcompat:1.4.2'
    implementation 'com.google.android.material:material:1.6.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    testImplementation 'junit:junit:4.13.2'
    androidTestImplementation 'androidx.test.ext:junit:1.1.3'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'

    def room_version = "2.4.2"

    //implementation "androidx.room:room-ktx:$room_version"

    implementation "androidx.room:room-runtime:$room_version"
    annotationProcessor "androidx.room:room-compiler:$room_version"
    //kapt "androidx.room:room-compiler:$room_version"

    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
}

User.kt

@Entity (tableName = "laptops")
data class User(
    @PrimaryKey val uid: Int,
    @ColumnInfo(name = "first_name") val firstName: String?,
    @ColumnInfo(name = "last_name") val lastName: String?
)

UserDao.kt

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

    @Query("SELECT * FROM user WHERE uid IN (:userIds)")
    suspend fun loadAllByIds(userIds: IntArray): List<User>

    @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
            "last_name LIKE :last LIMIT 1")
    suspend fun findByName(first: String, last: String): User

    @Insert
    suspend fun insertAll(vararg users: User)

    @Delete
    suspend fun delete(user: User)
}

AppDatabase.kt

@Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

MainActivity.kt

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val db = Room.databaseBuilder(
            applicationContext,
            AppDatabase::class.java, "laptops"
        ).build()

        val userDao = db.userDao()

        GlobalScope.launch(Dispatchers.Default) {
            userDao.insertAll(User(2,"Hello","World"))

            val users: List<User> = userDao.getAll()
            Log.d("Room Activity", users.toString())
        }


    }
}

Some of the older project, and a project from my friend have exactly the same code (as far as I have looked into it) and they are working fine. But now when I am trying to create new project it is giving me error. I have tried building several projects before posting here.


Solution

    1. (comment) doing this:
    val db = Room.databaseBuilder(
                applicationContext,
                AppDatabase::class.java, "laptops"
            ).build()
    

    in the onCreate of mainActivity is a very bad way of creating a database instance, unless you want multiple database instances in one app!

    1. solution:

    try changing your build.gradle to this:

    plugins {
        id 'com.android.application'
        id 'org.jetbrains.kotlin.android'
    }
    apply plugin: 'kotlin-kapt'
    
    android {
        compileSdk 32
    
        defaultConfig {
            applicationId "com.example.laptopsdb"
            minSdk 21
            targetSdk 32
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
        kotlinOptions {
            jvmTarget = '1.8'
        }
    }
    
    dependencies {
        implementation 'androidx.core:core-ktx:1.7.0'
        implementation 'androidx.appcompat:appcompat:1.4.2'
        implementation 'com.google.android.material:material:1.6.1'
        implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
        testImplementation 'junit:junit:4.13.2'
        androidTestImplementation 'androidx.test.ext:junit:1.1.3'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    
        def room_version = "2.4.2"
    
        kapt("androidx.room:room-compiler:2.4.2")
        implementation("androidx.room:room-runtime:2.4.2")
        implementation("androidx.room:room-ktx:2.4.2")
    
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
    }
    

    EDIT: After creating a project with the same code you have I noticed some rather strange bugs:

    1. in your User.kt file you declared the table name of that entity to "laptops", but in your UserDao you still refered to a table named user, which does not exist (???), that's why room had some troubles with your dao

    2. You declare your uid as Primary Key, which SHOULD NEVER be a duplicate, every single one of the keys should differ, yet in your main activity you use "userDao.insertAll(User(2,"Hello","World"))", which will result in a crash on second run, just remove that line

    3. using "GlobalScope.launch(Dispatchers.Default)" to run a coroutine isn't really encouraged, GlobalScope is even marked in the android studio as a delicate API and using it without proper knowledge first may result in strange bugs or even memory leaks, just use a viewModel to handle all of the work

    4. As I also stated before,

            val db = Room.databaseBuilder(
                applicationContext,
                AppDatabase::class.java, "laptops"
            ).build()
    

    do not use that to create database instance

    1. update your build.gradle to:
    plugins {
        id 'com.android.application'
        id 'org.jetbrains.kotlin.android'
    }
    apply plugin: 'kotlin-kapt'
    
    android {
        compileSdk 32
    
        defaultConfig {
            applicationId "com.example.laptopsdb"
            minSdk 21
            targetSdk 32
            versionCode 1
            versionName "1.0"
    
            testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        }
    
        buildTypes {
            release {
                minifyEnabled false
                proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
            }
        }
        compileOptions {
            sourceCompatibility JavaVersion.VERSION_1_8
            targetCompatibility JavaVersion.VERSION_1_8
        }
        kotlinOptions {
            jvmTarget = '1.8'
        }
    }
    
    dependencies {
    
        implementation 'androidx.core:core-ktx:1.7.0'
        implementation 'androidx.appcompat:appcompat:1.4.2'
        implementation 'com.google.android.material:material:1.6.1'
        implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
        testImplementation 'junit:junit:4.13.2'
        androidTestImplementation 'androidx.test.ext:junit:1.1.3'
        androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
    
        // you may add the variable, just keep the version correct
        implementation "androidx.room:room-runtime:2.5.0-alpha02"
        implementation "androidx.room:room-ktx:2.5.0-alpha02"
        kapt "androidx.room:room-compiler:2.5.0-alpha02"
    
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4")
        implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
    }
    

    and the dao to:

    @Dao
    interface UserDao {
        @Query("SELECT * FROM laptops")
        suspend fun getAll(): List<User>
    
        @Query("SELECT * FROM laptops WHERE uid IN (:userIds)")
        suspend fun loadAllByIds(userIds: IntArray): List<User>
    
        @Query("SELECT * FROM laptops WHERE first_name LIKE :first AND " +
                "last_name LIKE :last LIMIT 1")
        suspend fun findByName(first: String, last: String): User
    
        @Insert
        suspend fun insertAll(vararg users: User)
    
        @Delete
        suspend fun delete(user: User)
    }