Search code examples
androiddagger-hilt

Found unimplemented abstract methods, Did you forget to add a Dagger binding annotation (e.g. @Binds)?


I've been working on adapting code from the sunflower App tutorial, but it requires hilt to work now as well as using a @Provide annotation. I've added the annotations to the dao here below but now it is throwing this:

com/example/fittestapp/data/WorkoutDao.kt:16: [Hilt] Found unimplemented abstract methods, [getWorkouts(), getWorkout(java.lang.String), upsertAll(java.util.List<com.example.fittestapp.data.Workout>,kotlin.coroutines.Continuation<? super kotlin.Unit>)], in an abstract module, com.example.fittestapp.data.WorkoutDao. Did you forget to add a Dagger binding annotation (e.g. @Binds)? [1;31m[Hilt] Processing did not complete. See error above for details.[0m

import androidx.room.Dao
import androidx.room.Query
import androidx.room.Upsert
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ViewModelComponent
import dagger.hilt.components.SingletonComponent
import kotlinx.coroutines.flow.Flow

@Module
@InstallIn(SingletonComponent::class)
@Dao
interface WorkoutDao {


    @Query("SELECT * FROM workouts ORDER BY title")
    fun getWorkouts(): Flow<List<Workout>>


    @Query("SELECT * FROM workouts WHERE id  = :workoutId")
    fun getWorkout(workoutId: String): Flow<Workout>


    @Upsert
    suspend fun upsertAll(workouts: List<Workout>)
}

I am not sure to understand what's happening here, if I add binds to the methods it throws another error

Here is the rest of the code:

@Singleton class WorkoutRepository @Inject constructor(

private val routineDao: RoutineDao

) {

suspend fun createRoutine(workoutId: String) {
    val workoutRoutine = Routine(workoutId)
    routineDao.insertRoutine(workoutRoutine)
}

suspend fun removeGardenPlanting(routine: Routine) {
    routineDao.deleteRoutine(routine)
}

fun isSelected(workoutId: String) =
    routineDao.isSelected(workoutId)


fun getRoutine() = routineDao.getSelectedRoutine()


companion object {

    // For Singleton instantiation
    @Volatile private var instance: WorkoutRepository? = null

    fun getInstance(routineDao: RoutineDao) =
        instance ?: synchronized(this) {
            instance ?: WorkoutRepository(routineDao).also { instance = it }
        }
}

}

@HiltViewModel
class WorkoutAndRoutineListViewModel @Inject internal constructor(
    workoutRepository: WorkoutRepository
) : ViewModel() {
    val workoutAndRoutineSelected : Flow<List<WorkoutAndRoutineSelected>> =
        workoutRepository.getRoutine()
}

Thanks in advance


Solution

  • The issue is that you're trying to use your Dao interface as a Dagger module so the error occurs because the Dagger compiler is trying to process your Dao as a module.

    You need to define the Room database as an abstract class, which should have an abstract method to access the Dao (which Room will create for you):

    @Database(entities = [Workout::class], version = 1)
    abstract class WorkoutDatabase : RoomDatabase() {
        abstract fun workoutDao(): WorkoutDao
    }
    

    You could then create a Dagger module that creates the database instance and injects either the database or the Dao, something like this:

    @InstallIn(SingletonComponent::class)
    @Module
    object DatabaseModule {
    
        @Provides
        @Singleton
        fun provideWorkoutDatabase(@ApplicationContext context: Context): WorkoutDatabase =
            Room.databaseBuilder(context, WorkoutDatabase::class.java, "workout-db")
                .build()
    
        @Provides
        fun provideWorkoutDao(db: WorkoutDatabase): WorkoutDao = db.workoutDao()
    }
    

    Then you can inject it into your repository:

    class WorkoutRepository @Inject constructor(private val workoutDao: WorkoutDao) {
        ...
    }