hey all, I'm hoping someone can help me with somet...
# kodein
j
hey all, I'm hoping someone can help me with something here is there a way to access the binding tag from within the provider block? eg.:
Copy code
bind<Retrofit.Builder>(tag = AuthType.OAUTH) with provider {
        Retrofit.Builder()
            .client(instance<OkHttpClient>(tag = /* How do I access the tag used above on provider line? */))
            .addConverterFactory(JsonConverterFactory())
    }
the use case here is that for some cases, the provider block might be many lines, and I don't want to have to repeat the code for each new
AuthType
, so I was wondering can I just pass that through, rather than repeat the code each time. is something like this possible?
r
Hi, indeed this is possible. nevertheless. tag wont help you in this case.
If you need to pass arguments at retrieval, you should use
factory
binding, this is like provider, but with parameter.
giving you something like that
Copy code
bind<Retrofit.Builder>(tag = AuthType.OAUTH) with factory { param ->
        Retrofit.Builder()
            .client(instance<OkHttpClient>(tag = param))
            .addConverterFactory(JsonConverterFactory())
    }
and if you need to retrieve the same object regarding to the parameter, you should use
multiton
that could alos be called are singleton factory
j
thanks so much for the response, Romain
I can't seem to get it quite working, Kodein doesn't seem to recognise the factories when I attempt to use them
Copy code
org.kodein.di.Kodein$NotFoundException: No binding found for bind<Retrofit.Builder>(tag = "OAUTH") with ? { ? }
Available bindings for this type:
        module com.myframework.NetworkModule {
            bind<Retrofit.Builder>(tag = "OAUTH") with factory { AuthType -> Retrofit.Builder }
            bind<Retrofit.Builder>(tag = "EMAIL") with factory { AuthType -> Retrofit.Builder }
        }
it even lists the available bindings, and the one it says it can't find is actually identical to one in the list
r
Can you share your bindings declaration and your factory call ?
j
sure
this works:
Copy code
bind<Retrofit.Builder>(tag = AuthType.OAUTH) with provider {
        getRetrofitBuilder(okHttpClient = instance<OkHttpClient>(tag = AuthType.OAUTH))
    }
but this does not:
Copy code
bind<Retrofit.Builder>(tag = AuthType.OAUTH) with factory { authType ->
        getRetrofitBuilder(okHttpClient = instance<OkHttpClient>(authType))
    }
the second one compiles, but throws the aforementioned binding error at run-time
r
how do you retrieve your bindings? this is certainly where the error occurs
j
oh, right, my apologies
it's retrieved by another module, like this:
Copy code
bind<ApiService>() with provider {
    instance<Retrofit.Builder>(tag = AuthType.OAUTH)
        .baseUrl(AuthModule.BaseUrl)
        .build()
        .create(ApiService::class.java)
}
r
ok, I think this where the issue is, a factory is a function that needs an input parameter, in your case
authType
, the
tag
parameter of the
instance()
isn't a factory parameter, but a way to manage different instances of the same type. In your case I'm not sure that you need to tag your bindings.
Plus you should have named the type of your factory param. In your factory you also are doing something like
instance<OkHttpClient>(authType))
, this means that you also have another factory for the type
OkHttpClient
?
Is what I would have done (not tested)
OkHttpClient factory
Copy code
bind<OkHttpClient>() with factory { authType: AuthType ->
    OkHttpClient>(authType)
}
Retrofit.Builder factory
Copy code
bind<Retrofit.Builder>() with factory { authType: AuthType ->
    getRetrofitBuilder(okHttpClient = instance<OkHttpClient>(arg = authType))
}
ApiService provider
Copy code
bind<ApiService>() with provider {
    instance<Retrofit.Builder>(arg = AuthType.OAUTH)
        .baseUrl(AuthModule.BaseUrl)
        .build()
        .create(ApiService::class.java)
}
let me know if this help