Search code examples
androiddependency-injectionretrofitkoin

Dynamic urls with Koin ans Retrofit


Using Retrofit for network calls and Koin for dependency injection in an Android app, how to support dynamic url change?

(while using the app, users can switch to another server)

EDIT: network module is declared like this:

fun networkModule(baseUrl: String) = module {

    single<Api> {

        Retrofit.Builder()
                .baseUrl(baseUrl) 
                .client(OkHttpClient.Builder().readTimeout(30, TimeUnit.SECONDS)
                        .connectTimeout(30, TimeUnit.SECONDS)
                        .writeTimeout(30, TimeUnit.SECONDS)
                        .build())
                .build().create(Api::class.java)
    }

I am starting Koin in the Aplication class onCreate like this:

 startKoin {

        if (BuildConfig.DEBUG) AndroidLogger() else EmptyLogger()

        androidContext(this@App)

        modules(listOf(networkModule(TEST_API_BASE_URL), storageModule, integrationsModule, appModule))
    }

Solution

  • I've tried with Koin loading/unloading modules..and for a short period of time it worked, but later, after a minimal change I wasn't able to make it reload again.

    At the end, I solved it with wrapper object:

    class DynamicRetrofit(private val gson: Gson) {
    
    private fun buildClient() = OkHttpClient.Builder()
            .build()
    
    private var baseUrl = "https://etc..." //default url
    
    private fun buildApi() = Retrofit.Builder()
            .baseUrl(baseUrl)
            .addConverterFactory(GsonConverterFactory.create(gson))
            .client(buildClient())
            .build().create(MyApi::class.java)
    
    var api: MyApi = buildApi()
        private set
    
    fun setUrl(url: String) {
        if (baseUrl != url)
            baseUrl = url
    
        api = buildApi()
    }}
    

    I declare it in within Koin module like this:

      single<DynamicRetrofit>()
        {
            DynamicRetrofit(get(), get())
        }
    

    and use it in pretty standard way:

    dynamicRetrofit.api.makeSomeRequest()
    

    It was good solution for my case since I change baseUrl very rarely. If you need to make often and parallel calls to two different servers it will probably be inefficient since you this will recreate HTTP client often.