Lingo
Lingo

Reputation: 600

Dagger2 Inject class with parameter (using Room)

I have a problem with injecting classes with Dagger2. I am using RoomDatabase for database access.

My room setup:

Dao's

interface noteDao()
interface noteTypeDao()
interface userDao()

NoteRepository

@Singleton
class NoteRepository @Inject constructor(
    private val noteDao: NoteDao,
    private val noteTypeDao: NoteTypeDao,
    private val userDao: UserDao
) {

}

AppDatabase

@Database(entities = [Note::class, User::class, NoteType::class], version = 1)
abstract class AppDatabase : RoomDatabase() {

    abstract fun noteDao(): NoteDao
    abstract fun userDao(): UserDao
    abstract fun noteTypeDao(): NoteTypeDao

    companion object {
        @Volatile
        private var INSTANCE: AppDatabase? = null

        fun getDatabase(context: Context): AppDatabase {
            val tempInstance = INSTANCE
            if (tempInstance != null) {
                return tempInstance
            }
            synchronized(this) {
                val instance = Room.databaseBuilder(
                    context.applicationContext,
                    AppDatabase::class.java,
                    "NoteDatabase"
                ).build()
                INSTANCE = instance
                return instance
            }
        }
    }
}

Dagger 2 setup:

AppModule

@Module
class AppModule {

    @Provides
    fun provideNoteRepository(app: Application): NoteRepository {
        return NoteRepository(
            AppDatabase.getDatabase(app).noteDao(),
            AppDatabase.getDatabase(app).noteTypeDao(),
            AppDatabase.getDatabase(app).userDao()
        )
    }

    @Provides
    fun provideApplication(): Application {
        return Application()
    }

}

AppComponent

@Component(modules = [AppModule::class])
interface AppComponent {
    fun inject(app: MainActivity)
}

I am getting a NullPointerExeption int the AppDatabase in the line context.applicationContext. Any suggetion how to solve the problem? It seems that the AppDatabase doesnt get the application instance from Dagger2.

Upvotes: 0

Views: 1334

Answers (1)

zsmb13
zsmb13

Reputation: 89668

Application is a framework class, you can not just instantiate it yourself by calling its constructor. Instead, you need to pass in your application that the framework instantiates for you into your module, and provide that:

@Module
class AppModule(val application: Application) { 
    ...

    @Provides
    fun provideApplication(): Application {
        return application
    }
}

Now, if you were creating your AppComponent like this before, in your application's onCreate (presumably, as that's the usual way to do it):

override fun onCreate() {
    injector = DaggerAppComponent.create()
}    

You'd have to replace it with something like this, passing in your application instance to the module so that it can then provide it:

override fun onCreate() {
    injector = DaggerAppComponent.builder()
            .appModule(appModule(this))
            .build()
}

Upvotes: 2

Related Questions