首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在非(活动、服务、片段、应用程序)类中是否有使用注入器的方法?

在非(活动、服务、片段、应用程序)类中是否有使用注入器的方法?
EN

Stack Overflow用户
提问于 2020-03-31 16:47:27
回答 3查看 331关注 0票数 1

我们在应用程序中使用Dagger2。我正在尝试做一个房间数据库,我正在编写存储库代码,但是我想为类注入应用程序上下文和DAO。

我有一种感觉,你只能在碎片,活动,服务,应用等中注射匕首。

我现在拥有的是:

代码语言:javascript
复制
class DownloadsDataRepositoryImpl : IDownloadsDataRepository, HasAndroidInjector {

      @Inject
      lateinit var androidInjector : DispatchingAndroidInjector<Any>

      @Inject
      lateinit var downloadsDao: DownloadsDao

      override fun androidInjector(): AndroidInjector<Any> = androidInjector
      init { 
         androidInjector()
      }

}

但我肯定这行不通。有办法吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-03-31 19:12:15

如前所述,匕首-android只是一个工具,用来帮助注入无法控制其创建的特定框架类。

正确的方法是使用简单的施工注射

为了更直接地了解应该如何在@Component上公开它,我需要更多的代码,特别是关于您的活动/片段的代码,但是下面是一个粗略的示例(我没有测试这个示例,如果有一些小错误,您可以在编译器错误消息之后修复它们):

首先,您将有一些公开您的DAO的对象。可能是房间?

代码语言:javascript
复制
@Entity(tableName = "download_table")
data class DownloadEntity(
    @PrimaryKey
    val key: String
)

@Dao
interface DownloadsDao {
    @Query("SELECT * FROM download_table")
    fun load(): List<DownloadEntity>
}

@Database(
    entities = [DownloadEntity::class], version = 1
)
abstract class DownloadRoomDatabase : RoomDatabase() {
    abstract val downloadsDao: DownloadsDao
}

现在,我们将创建一个使用@Inject注释构建的粗糙存储库。匕首会帮我们建造这个物体的。请注意,我没有使用匕首-android:

代码语言:javascript
复制
interface IDownloadsDataRepository

class DownloadsDataRepositoryImpl @Inject constructor(
    val downloadsDao: DownloadsDao
) : IDownloadsDataRepository

如何将其公开给您的活动/片段/服务需要更多关于您的实现的细节。例如,如果它在ViewModel或使用@Inject注释的Presenter中,或者您正在直接访问您的活动,则会产生不同的实现。如果没有更多的详细信息,我将假设您直接访问您的活动上的存储库:

代码语言:javascript
复制
class DownloadActivity : FragmentActivity() {

    @Inject
    lateinit val repo: IDownloadsDataRepository

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        DaggerDownloadComponent.factory().create(this).inject(this)
    }
}

现在我们需要指示Dagger如何:

  1. 将具体的DownloadsDataRepositoryImpl绑定到活动所需的IDownloadsDataRepository接口
  2. 如何提供构建DownloadsDataRepositoryImpl的依赖项

为此,我们需要一个模块

代码语言:javascript
复制
@Module
abstract class RepositoryModule {

    //We will bind our actual implementation to the IDownloadsDataRepository
    @Binds
    abstract fun bindRepo(repo: DownloadsDataRepositoryImpl): IDownloadsDataRepository


    @Module
    companion object {

        //We need the database to get access to the DAO
        @Provides
        @JvmStatic
        fun provideDataBase(context: Context): DownloadRoomDatabase =
            Room.databaseBuilder(
                context,
                DownloadRoomDatabase::class.java,
                "download_database.db"
            ).build()

        //With the database, we can provide the DAO:
        @Provides
        @JvmStatic
        fun provideDao(db: DownloadRoomDatabase): DownloadsDao = db.downloadsDao
    }
}

这样,我们就可以完成拼图的最后一部分,创建@Component

代码语言:javascript
复制
@Component(
    modules = [
        RepositoryModule::class
    ]
)
interface DownloadComponent {

    fun inject(activity: DownloadActivity)

    @Component.Factory
    interface Factory {
        fun create(context: Context): DownloadComponent
    }
}

请注意,我没有使用任何dagger-android代码,我不认为它很有用,而且会造成不必要的混乱。坚持使用基本的dagger2结构,您就可以了。您只需了解这些构造是如何工作的,就可以实现99.9%的应用程序:

@Module@Component@Subcomponent

编辑:正如注释中所述,如果实际使用作用域,则可能需要正确管理存储库的作用域,特别是DB创建。

票数 2
EN

Stack Overflow用户

发布于 2020-03-31 17:16:52

不确定如何实现匕首,但下面是一个示例,您可以为非活动类提供上下文。

假设您有AppModule类,那么您可以在那里添加provideContext()方法:

代码语言:javascript
复制
@Module
class AppModule(app: App) {

    private var application: Application = app

    @Provides
    fun provideContext(): Context {
        return application
    }
}

下面是用Kotlin编写的非活动类:

类Utils @inject构造函数(私有val上下文: Context) { ..}

就这样,重建j

票数 1
EN

Stack Overflow用户

发布于 2020-04-01 01:00:16

我有一种感觉,你只能在碎片,活动,服务,应用等中注射匕首。

在Dagger-Android2.20之前,但在2.20+之后,你的假设是正确的。

现在您可以为任何类创建一个@ContributesAndroidInjector,这将为添加了@ContributesAndroidInjectorT生成一个@ContributesAndroidInjector

这意味着有一个多绑定,允许您为T获取一个T,这就是HasAndroidInjector为您所做的。

因此,以下内容在另一种情况下适用于我(针对工作经理中的成员注射工人,而不是创建多绑定和工厂):

代码语言:javascript
复制
@Keep
class SyncWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    init {
        val injector = context.applicationContext as HasAndroidInjector
        injector.androidInjector().inject(this)
    }

    @Inject
    lateinit var apiService: ApiService

代码语言:javascript
复制
@ContributesAndroidInjector
abstract fun syncWorker(): SyncWorker

然而,在您的特殊情况下,这是不需要的。

Dagger-Android是用于使用自动生成的子组件的成员注入类,通常只有在注入类型位于不同模块内时才需要这些子组件,因此不能将fun inject(T t)直接添加到AppComponent中,否则看不到AppComponent

在您的例子中,简单的构造函数注入就足够了,因为您拥有自己的类。

代码语言:javascript
复制
@Singleton
class DownloadsDataRepositoryImpl @Inject constructor(
    private val downloadsDao: DownloadsDao
): IDownloadsDataRepository {}

,您可以通过模块绑定

代码语言:javascript
复制
@Module
abstract class DownloadsModule {
    @Binds
    abstract fun dataRepository(impl: DownloadsDataRepositoryImpl): IDownloadsDataRepository
}

否则,您只需在Application.onCreate()中创建组件实例即可。

代码语言:javascript
复制
@Component(modules = [DownloadsModule::class])
@Singleton
interface AppComponent {
    fun dataRepository(): DownloadsDataRepository

    @Component.Factory
    interface Factory {
        fun create(@BindsInstance appContext: Context): AppComponent
    }
}

代码语言:javascript
复制
class CustomApplication: Application() {
    lateinit var component: AppComponent
        private set

    override fun onCreate() {
        super.onCreate()
        component = DaggerAppComponent.factory().create(this)
    }
}

然后你就可以得到它

代码语言:javascript
复制
val component = (context.applicationContext as CustomApplication).component

尽管从技术上讲,您可以创建一个扩展函数。

代码语言:javascript
复制
val Context.appComponent: AppComponent
    get() = (applicationContext as CustomApplication).component

val component = context.appComponent
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60955695

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档