Android Hilt dagger 在 vi​​ewModel @ViewModelInject 中注入接口得到 UninitializedPropertyAccessException

UmA*_*orn 6 android dependency-injection android-viewmodel dagger-hilt

我尝试使用 Hilt codelab https://codelabs.developers.google.com/codelabs/android-hilt#10

它与 Activity 和 Fragment 配合良好

记录器是 RoomDB

然后我尝试用这篇文章将记录器注入到 viewModel 中

通过添加

implementation "androidx.hilt:hilt-lifecycle-viewmodel
    :1.0.0-alpha02"
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
Run Code Online (Sandbox Code Playgroud)

查看模型代码

class RecordFragmentViewModel @ViewModelInject constructor(@Assisted private val savedStateHandle: SavedStateHandle) :
    ViewModel() {
    @DatabaseLogger
    @Inject
    lateinit var logger: LoggerDataSource
Run Code Online (Sandbox Code Playgroud)

要注入的类记录器

 class LoggerLocalDataSource 
@Inject constructor(private val logDao: LogDao) : LoggerDataSource {
Run Code Online (Sandbox Code Playgroud)

日志记录模块

@Qualifier
annotation class InMemoryLogger

@Qualifier
annotation class DatabaseLogger

@InstallIn(ApplicationComponent::class)
@Module
abstract class LoggingDatabaseModule {

    @DatabaseLogger
    @Singleton
    @Binds
    abstract fun bindDatabaseLogger(impl: LoggerLocalDataSource): LoggerDataSource
}

@InstallIn(ActivityComponent::class)
@Module
abstract class LoggingInMemoryModule {

    @InMemoryLogger
    @ActivityScoped
    @Binds
    abstract fun bindInMemoryLogger(impl: LoggerInMemoryDataSource): LoggerDataSource
}
Run Code Online (Sandbox Code Playgroud)

数据库模块

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

    @Provides
    @Singleton
    fun provideDatabase(@ApplicationContext appContext: Context): AppDatabase {
        return Room.databaseBuilder(
            appContext,
            AppDatabase::class.java,
            "logging.db"
        ).build()
    }

    @Provides
    fun provideLogDao(database: AppDatabase): LogDao {
        return database.logDao()
    }
}
Run Code Online (Sandbox Code Playgroud)

编译并运行没有错误。但是,我使用调试来观察记录器及其获取。

Method threw 'kotlin.UninitializedPropertyAccessException' exception.
Run Code Online (Sandbox Code Playgroud)

我在运行时调用 logger.something() 抛出异常

Fatal Exception: kotlin.UninitializedPropertyAccessException
lateinit property logger has not been initialized
Run Code Online (Sandbox Code Playgroud)

更多信息 https://dagger.dev/hilt/migration-guide.html

https://codelabs.developers.google.com/codelabs/android-hilt#10

https://medium.com/mobile-app-development-publication/injecting-viewmodel-with-dagger-hilt-54ca2e433865

UmA*_*orn 4

由于 LoggerDataSource 是一个接口,我们需要指定需要注入哪个实现。感谢@Andrew提出注入构造函数的想法

class RecordFragmentViewModel
@ViewModelInject
constructor(@Assisted private val savedStateHandle: SavedStateHandle,
            @DatabaseLogger private val logger: LoggerDataSource) :
    ViewModel(), LifecycleObserver {
Run Code Online (Sandbox Code Playgroud)

指定

@Qualifier
annotation class InMemoryLogger

@Qualifier
annotation class DatabaseLogger

@InstallIn(ApplicationComponent::class)
@Module
abstract class LoggingDatabaseModule {

    @DatabaseLogger
    @Singleton
    @Binds
    abstract fun bindDatabaseLogger(impl: LoggerLocalDataSource): LoggerDataSource
}

@InstallIn(ActivityComponent::class)
@Module
abstract class LoggingInMemoryModule {

    @InMemoryLogger
    @ActivityScoped
    @Binds
    abstract fun bindInMemoryLogger(impl: LoggerInMemoryDataSource): LoggerDataSource
}
Run Code Online (Sandbox Code Playgroud)