Boysteuf
Boysteuf

Reputation: 253

DAO Injection problem - RoomDatabase not found with Hilt Android

So I'm trying to use Room on a personnal project. I have implemented my entities, dao and my roomdatabase extended application class :

@Database(
version = 1,
entities = [
    UserDBEntity::class
]
)
abstract class MyDatabase: RoomDatabase() {

    companion object {
        const val DATABASE_NAME = "MyDb"
    }

    abstract fun getUserDao(): UserDao
}

However, I'm also trying to use Hilt DI with it, so, I created a module like that :

@InstallIn(ApplicationComponent::class)
@Module
object PersistenceModule {

    lateinit var database: MyDatabase

    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext context: Context): MyDatabase{
        database =  Room.databaseBuilder(
            context,
            MyDatabase::class.java,
            MyDatabase.DATABASE_NAME
        )
            .fallbackToDestructiveMigration()
            .build()

        return database
    }

    @Provides
    @Singleton
    fun provideUserDao(db: MyDatabase): UserDao {
        return db.getUserDao()
    }
}

Everything seems good to me. However, when I try to compile, I've got this error message :

class file for androidx.room.RoomDatabase not found

Any idea of what I missed ?

If it can help you, I tried to change my build.gradle from this :

implementation "androidx.room:room-runtime:2.3.0-alpha02"

To this :

api "androidx.room:room-runtime:2.3.0-alpha02"

And with that, it compiles succefully, but I don't think it's a good practice, looking the tutorials I found.

Don't hesitate if you need more details on my code.

Thank you for your answers :)

EDIT :

My build.gradle for Room :

implementation "androidx.room:room-runtime:2.3.0-alpha02"
kapt "androidx.room:room-compiler:2.3.0-alpha02"
implementation "android.arch.persistence.room:runtime:1.1.1"
kapt "android.arch.persistence.room:compiler:1.1.1"

With this also :

apply plugin: 'kotlin-kapt'

EDIT 2 :

I think I found what is the cause of the problem. I called my DAO method in a class like that :

@Singleton
class DBManagerImpl @Inject constructor(
    private val userDao: UserDao
) : DBManager {

    override fun insertUser(userDBEntity: UserDBEntity) {
       userDao.insertUser(userDBEntity)
    }
}

It seems the problem is in the userDao injection cause if I comment the "private val userDao: UserDao" line, I don't have the error anymore. So I think my problem comes from my way to inject the dao object.

Upvotes: 4

Views: 3690

Answers (7)

Denis Zozulinsky
Denis Zozulinsky

Reputation: 27

Try "api "androidx.room:room-runtime:2.3.0-alpha02"" instead of "implementation "androidx.room:room-runtime:2.3.0-alpha02"". I don't know why, but it worked for me

Upvotes: 1

Anter
Anter

Reputation: 3625

I faced that problem because I was adding dependencies of room to the core module so for those who using modular architecture be sure you added dependencies of room to the app module also

Upvotes: 5

Andrii Turkovskyi
Andrii Turkovskyi

Reputation: 29458

I had the same problem. It can be fixed with Dagger, but not with Hilt. At least, for now. It seems that for now best solution is using api instead of implementation. If you strongly want to avoid it, you can use something like this:

@InstallIn(ApplicationComponent::class)
@Module
object PersistenceModule {

    lateinit var database: MyDatabase
    
    private fun getDatabase(context: Context): MyDatabase {
            if (!::database.isInitialized) {
                database = Room.databaseBuilder(
                    context,
                    MyDatabase::class.java,
                    MyDatabase.DATABASE_NAME
                )
                    .fallbackToDestructiveMigration()
                    .build()
            }
            return database
        
    }

    @Provides
    @Singleton
    fun provideUserDao(@ApplicationContext context: Context): UserDao {
        return getDatabase(context).getUserDao()
    }
}

But, as I've said - maybe for now it's better to leave api in gradle

Upvotes: 1

Alektas
Alektas

Reputation: 656

If you are using multiple modules, try adding dependencies to the App module too:

build.gradle (app)

implementation "androidx.room:room-runtime:${versions.androidx_room}"
implementation "androidx.room:room-ktx:${versions.androidx_room}"
kapt "androidx.room:room-compiler:${versions.androidx_room}"

Upvotes: 1

Andrew
Andrew

Reputation: 4732

Since you did not provide how you created your dao object, I've written my own and provide it in this answer. This should work:

Database Class

@Database(version = 1,entities = [UserDBEntity::class])
abstract class MyDataBase() : RoomDatabase() {
    
   abstract fun myDao(): UserDao

   companion object {
      val DATABASE_NAME = "my_db"
   }
}

DAO

@Dao
inteface UserDao {
   // your functions
   @Query("SELECT * FROM UserDBEntity")
   suspend fun get(): List<User>

   @Insert(onConflict = OnConflictStrategy.REPLACE)
   suspend fun insert(entity: UserDBEntity)
}

Room Module

@InstallIn(ApplicationComponent::class)
@Module
object RoomModule {
   @Singleton
   @Provides
   fun provideMyDB(@ApplicationContext context: Context): MyDataBase {
       return Room.databaseBuilder(context, 
               MyDataBase::class.java,
               MyDataBase.DATABASE_NAME
         ).fallbackToDestructiveMigration().build()
   }
}

@Singleton
@Provides
fun provideMyDao(myDB: MyDataBase): UserDao {
    return myDB.myDao()
}

Upvotes: 1

Boysteuf
Boysteuf

Reputation: 253

OK, so, it seems that this is working :

lateinit var database: MyDatabase

@Provides
@Singleton
fun provideDatabase(@ApplicationContext context: Context): MyDatabase{
    database = Room.databaseBuilder(
        context,
        MyDatabase::class.java,
        MyDatabase.DATABASE_NAME
    )
        .fallbackToDestructiveMigration()
        .build()

    return database
}


@Provides
@Singleton
fun provideUserDao(): UserDao {
    return database.getUserDao()
}

Actually, I have to reuse the database variable on all my dao providing. I don't yet understand why, I keep searching.

EDIT :

Nevermind ... it works on compile but not when I launch the app :

lateinit property database has not been initialized

Upvotes: 0

Do you have 2 lines in app gradle file:

apply plugin: 'kotlin-kapt'

kapt "androidx.room:room-compiler:2.2.5"

Upvotes: 0

Related Questions