是否可以创建同一对象的不同实例并通过将参数传递给 Koin 中的 get() 函数来访问它们?

Posted

技术标签:

【中文标题】是否可以创建同一对象的不同实例并通过将参数传递给 Koin 中的 get() 函数来访问它们?【英文标题】:Is it possible to create different instances of the same object and access them by passing parameters to get() function in Koin? 【发布时间】:2022-01-16 18:03:46 【问题描述】:

我正在使用 Koin 作为我的应用程序的 DI。我创建了一个模块:

object NetworkModule 
    fun get() = module 
        single 
            val authenticationInterceptor = Interceptor  chain ->
                // Request customization goes here
            

            OkHttpClient.Builder()
                .connectTimeout(15, TimeUnit.SECONDS)
                .readTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(60, TimeUnit.SECONDS)
                .addInterceptor(authenticationInterceptor) //Not all clients might have this interceptor
                .build()
        

        single 
            Retrofit.Builder()
                .baseUrl("example.com")
                .client(get(/* I would like to send some paramter here */))
                .addConverterFactory(GsonConverterFactory.create(get()))
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build()
                .create(Api::class.java)
        
     


如何创建具有不同参数集或具有不同实例化的不同HttpClientRetrofit 实例?例如,在某些情况下,我可能需要 OkHttpClientAutheniticationInterceptor,而在其他一些情况下,我的客户可能不需要使用它。

可以在调用get()的时候传递一些参数,这样就可以得到不同的实例吗?任何建议都会受到重视。

【问题讨论】:

【参考方案1】:

您可以使用命名属性 - 例如

single<OkHttpClient>(named("auth"))
// here you pass the version with authinterceptor

single<OkHttpClient>(named("noAuth"))
// here you pass the version without authinterceptor

然后在您的 get() 方法中传递名称,例如

.client(get(named("auth")))

【讨论】:

^ 这就是我在当前项目中的做法。 @r2rek 感谢您的回复。你能更清楚地解释我现在如何访问这个模块吗?喜欢var myVariable = NetworkModule.get() 基本上你也会有两个你的 Api 接口实例,例如` single("authApi") Retrofit.Builder() .baseUrl(Const.BASE_API_URL) .client(get("auth")) .addConverterFactory(GsonConverterFactory.create(get())) .addCallAdapterFactory(RxJava2CallAdapterFactory.create() ) .build() .create(Api::class.java) ` 我明白这一点。我想我的问题并不清楚。我实际上问的是“我现在如何使用这两个 Retrofit 实例”?喜欢这个val api: Api = get("auth") ? 这取决于您将在哪里使用它。如果您将在模块的构造函数中使用它,那么是的,get("auth") 将是要走的路。但是,如果您将直接注入它,那么 inject("auth").【参考方案2】:

你可以像下面这样(使用 koin 最新版本的命名属性)。还有为什么我使用 single 和 factory 因为

single——声明给定类型的单例定义。 Koin 只保留此定义的一个实例

factory — 声明给定类型的工厂定义。 Koin 给出了一个新的 每次实例

const val WITH_AUTH: String = "WITH_AUTH"
const val WITH_OUT_AUTH: String = "WITH_OUT_AUTH"

val remoteModule = module 
factory(named("HEADERS")) 
        val map = it.get<MutableMap<String, String>>(0)
        Interceptor  chain ->
            val original = chain.request()
            val request = original.newBuilder()
            map.forEach  entry ->
                request.addHeader(entry.key, entry.value)
            
            chain.proceed(request.build())
        
    

factory(named("auth")) 
        OkHttpClient.Builder().apply 
            map["AUTHORIZATION"] = "token"

            readTimeout(1, TimeUnit.MINUTES)
            connectTimeout(2, TimeUnit.MINUTES)
            writeTimeout(1, TimeUnit.MINUTES)
            addInterceptor(get(named("HEADERS"), parameters = 
               parametersOf(map)
            ))
        .build()
    

factory(named("auth")) 
        Retrofit.Builder()
                .baseUrl("base_url")
                .client(get(named("auth")))
                //.addCallAdapterFactory()
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(ApiService::class.java)
    

single(named("noAuth")) 
        val map = mutableMapOf(ACCEPT to CONTENT_TYPE)
        OkHttpClient.Builder().apply 
            readTimeout(1, TimeUnit.MINUTES)
            connectTimeout(2, TimeUnit.MINUTES)
            writeTimeout(1, TimeUnit.MINUTES)
            addInterceptor(get(named("HEADERS"), parameters = 
                parametersOf(map)
            ))
          
        .build()
    

single(named("noAuth")) 
        Retrofit.Builder()
                .baseUrl("base_url")
                .client(get(named("noAuth")))
                //.addCallAdapterFactory()
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(ApiService::class.java)
    

现在在您的活动或视图模型中

protected val apiServiceWithoutHeader: ApiService by inject(named(WITH_OUT_HEADER))
protected val apiServiceWithHeader: ApiService by inject(named(WITH_HEADER))

用上述对象调用适当的 API

【讨论】:

我想问这之后的下一步是什么?如何在同一活动中在“noAuth”和“auth”之间切换? @QuanNguyen :我已经更新了我的答案,如果您发现任何问题,请告诉我 a,感谢您提供更新的答案。我应该解释更多。我正在使用 MVVM 架构,有数据源、存储库、视图模型等。在 2 个改造实例旁边的 koin 模块中,我也有 single providePostService(get(named(getProperty(RETROFIT_CHOOSE_NAMESPACE)) )) 我想要在同一个活动中(不在 onCreate 上),登录后,我想要将改造切换到 RETROFIT_LOGGED_NAMESPACE 我调用 getKoin().setProperty(RetrofitObject.RETROFIT_CHOOSE_NAMESPACE, RetrofitObject.RETROFIT_LOGGED_NAMESPACE) 它没有做任何事情

以上是关于是否可以创建同一对象的不同实例并通过将参数传递给 Koin 中的 get() 函数来访问它们?的主要内容,如果未能解决你的问题,请参考以下文章

可以将参数传递给 TestNG DataProvider?

将类对象传递给 Drools 规则 (drt) 文件

将表值参数传递给具有不同字段数的存储过程

将上下文传递给许多方法是否正常?

如何将向量作为参数传递给另一个向量?

如何将具有多个对象的状态数组作为参数传递给graphql突变?