【问题标题】:Hilt injecting child class as parent typeHilt 注入子类作为父类型
【发布时间】:2021-01-25 20:43:48
【问题描述】:

我有 3 个存储库:

interface MainRepository {
        ...
    }

interface LocalRepository {
        ...
    }

interface WebRepository {
        ...
    }

每个存储库都有自己的实现:

@Singleton
class MainRepositoryImpl @Inject constructor(
    private val localRepository: LocalRepository,
    private val webRepository: WebRepository
) : MainRepository {
...
}

@Singleton
class LocalRepositoryImpl @Inject constructor(
    private val localMapper: LocalMapper
    private val popularMovieDao: PopularMovieDao
) : LocalRepository {
...
}

@Singleton
class WebRepositoryImpl @Inject constructor(
    private val webMapper: WebMapper,
    private val popularMovieApi: PopularMovieApi
) : WebRepository {
...
}

如您所见,MainRepository 需要将其他两个存储库都注入其中,但是,我真的不知道该怎么做。

当然,我可以使用 LocalRepositoryImplWebRepositoryImpl 类型注入它,但我想使用 LocalRepositoryWebRepository 类型注入它以获得更通用的方法。

这是我尝试编写的模块:

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

    @Singleton
    @Provides
    fun provideWebRepository(): WebRepository {
        return WebRepositoryImpl(mapper = WebMapper(), popularMovieApi = PopularMovieApi.getInstance())
    }

    @Singleton
    @Provides
    fun provideLocalRepository(): LocalRepository {
        return LocalRepositoryImpl(mapper = LocalMapper(), // Here I can't really 
            // figure out how to get @Dao since it requires DB 
            // which requires context and etc 
            // which makes me think that I've got completely wrong approach to this)
    }
}

我的 LocalData 模块:

@InstallIn(ApplicationComponent::class)
@Module
object LocalDataSourceModule {
    @Singleton
    @Provides
    fun provideMainDatabase(@ApplicationContext context: Context): MainDatabase = MainDatabase.getInstance(context)

    @Provides
    fun providePopularMovieDao(mainDatabase: MainDatabase): PopularMovieDao = mainDatabase.popularMovieDao()
}

我的 WebData 模块:

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

    @Singleton
    @Provides
    fun providePopularMovieApi(): PopularMovieApi = PopularMovieApi.getInstance()
}

如何在维护接口类型(LocalRepository 和`WebRepository)的同时正确地注入我拥有的实现(LocalRepositoryImplWebRepositoryImpl)??

【问题讨论】:

    标签: android kotlin dependency-injection dagger-hilt


    【解决方案1】:

    使用@Binds。而不是你的object Module 使用以下模块:

    @InstallIn(ApplicationComponent::class)
    @Module
    interface Module {
    
        @Binds
        fun bindWebRepository(repository: WebRepositoryImpl): WebRepository
    
        @Binds
        fun bindLocalRepository(repository: LocalRepositoryImpl): LocalRepository
    }
    

    它告诉 Dagger 如果你需要 WebRepository 依赖,那么它必须提供 WebRepositoryImpl 并且对于 LocalRepositoryLocalRepositoryImpl 也是如此。

    What is the use case for @Binds vs @Provides annotation in Dagger2

    【讨论】:

    • @Andrew 你的意思,@Binds 做 R'J 想要的。而且您的解决方案与手动 DI 没有什么不同
    • 不,没有!正如 R.J 所说,他不希望 WebRepositoryImpl 作为他的参数,只希望 WebRepository。因此,他必须使用@Provides
    • @Andrew He 表示 MainRepositoryImpl 中的参数...
    • @Andrew 其实这里需要
    • 在您的两个 cmets 之间,我有 2 个解决方案。 @Andrew 的解决方案正在发挥作用,他提供了很多见解。但是,您的解决方案要简洁得多,而且效果也很好,我绝对更喜欢。
    【解决方案2】:

    您的存储库

    interface MainRepository {
            ...
    }
    
    interface LocalRepository {
            ...
    }
    
    interface WebRepository {
            ...
    }
    

    实现(这里没有@Inject 或@Singleton!)

    class MainRepositoryImpl constructor(
        private val localRepository: LocalRepository,
        private val webRepository: WebRepository
    ) : MainRepository {
    ...
    }
    
    
    class LocalRepositoryImpl constructor(
        private val localMapper: LocalMapper
        private val popularMovieDao: PopularMovieDao
    ) : LocalRepository {
    ...
    }
    
    
    class WebRepositoryImpl constructor(
        private val webMapper: WebMapper,
        private val popularMovieApi: PopularMovieApi
    ) : WebRepository {
    ...
    }
    

    Di.Module(存储库模块)

    @Module
    @InstallIn(ApplicationComponent::class)
    object RepositoryModule {
        
     @Singleton
     @Provides
     fun provideMainRepository(
               localRepository: LocalRepository,
               webRepository: WebRepository
     ): MainRepository = MainRepositoryImpl(localRepository, webRepository)
    
     @Singleton
     @Provides
     fun provideLocalRepository(
            localMapper: LocalMapper,
            popularMovieDao: PopularMovieDao
     ): LocalRepository = LocalRepositoryImpl(localMapper, popularMovieDao)
    
     @Singleton
     @Provides
     fun provideWebRepository(
            webMapper: WebMapper,
            popularMovieApi: PopularMovieApi
     ): WebRepository = WebRepositoryImpl(webMapper, popularMovieApi)
    

    试试这个,告诉我它是否有效。由于您已使用 @Provides 提供了所有存储库,因此 Dagger-Hilt 知道如何创建它们。您是否在本地数据库中使用Room?如果是,那么像您那样创建数据库可能不正确。如果您不使用Room,您应该开始使用它,因为它让您的生活更轻松。

    下面是用匕首创建房间数据库的正确方法:

    实体模块

    @Entity(tableName = "exampleTableName")
    data class ExampleEntity(
        @PrimaryKey(autoGenerate = true)
        val id: Int,
        // ... whatever you need
        val header: String = "",
        val title: String = "",
        val description: String = "",
    )
    

    示例数据库

    @Database(entities = [ExampleEntity::class], version = 1)
    abstract class ExampleDatabase : RoomDatabase() {
        abstract fun exampleDao(): ExampleDao
    
        companion object {
            const val DATABASE_NAME = "example_db"
        }
    }
    

    DAO

    @Dao
    interface DocumentDao {
        @Insert(onConflict = OnConflictStrategy.REPLACE)
        suspend fun insert(exampleEntity: List<ExampleEntity>)
    
        @Query("SELECT * FROM exampleTableName")
        suspend fun getList(): List<ExampleEntity>
    }
    

    房间分区模块

    @Module
    @InstallIn(ApplicationComponent::class)
    object RoomModule {
    
        @Singleton
        @Provides
        fun provideExampleDB(@ApplicationContext context: Context): ExampleDatabase = Room.databaseBuilder(
            context,
            ExampleDatabase::class.java,
            ExampleDatabase.DATABASE_NAME,
        ).fallbackToDestructiveMigration().build()
    
        @Singleton
        @Provides
        fun provideExampleDAO(exampleDatabase: ExampleDatabase): ExampleDao = exampleDatabase.exampleDao()
    
      }
    

    【讨论】:

    • 我在写这篇文章时更改了代码。要回答您的问题 - 是的,我正在使用 Room,但是,不确定创建数据库的正确方法是什么
    • 您的解决方案非常有效。此外,修复了我的 Room DB 创建。非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-30
    • 2016-06-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多