You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合Retrofit2与Koin2.0实时修改Base URL

结合Koin与Retrofit实现Base URL实时动态修改

针对你的需求,我整理了两种可行的方案,结合你现有的模块代码来实现动态切换Base URL:

方案一:重新加载Koin模块替换Retrofit实例

Retrofit实例创建后其Base URL是不可变的,所以我们可以通过重新创建包含新Base URL的NetworkModule,并让Koin替换掉旧的网络实例来实现切换。

步骤1:调整Repository的依赖方式

你的Repository目前是single单例,会持有旧的Retrofit实例。为了让它能使用新的Retrofit,需要调整依赖方式:

  • 要么将Repository改为factory(每次获取都是新实例,会注入最新的Retrofit):
fun createMainModule(context: Context) = module { 
    single(named(APP_CONTEXT)) { context } 
    single(named(RESOURCES)) { context.resources } 
    factory(named(REPOSITORY)) { Repository(get(named(RETROFIT))) } // 改成factory
}
  • 要么让Repository依赖Provider<Retrofit>,每次调用时获取最新实例:
// Repository类调整
class Repository(private val retrofitProvider: Provider<Retrofit>) {
    private val api get() = retrofitProvider.get().create(YourApi::class.java)
    // ... 其他方法
}

// createMainModule中调整
fun createMainModule(context: Context) = module { 
    single(named(APP_CONTEXT)) { context } 
    single(named(RESOURCES)) { context.resources } 
    single(named(REPOSITORY)) { Repository(getProvider(named(RETROFIT))) } 
}

步骤2:用户选择服务器后重新加载模块

当用户从服务器列表中选择了目标服务器,获取其Base URL后,调用Koin的loadKoinModules方法重新加载NetworkModule:

// 假设用户选择后得到新的baseUrl
val newBaseUrl = "https://new-server.example.com/"
loadKoinModules(createNetworkModule(newBaseUrl))

你的createNetworkModule已经设置了override = true,所以新的RETROFIT、OK_HTTP等实例会替换掉旧的,后续网络请求就会使用新的Base URL。


方案二:使用OkHttp拦截器动态修改URL

这种方案不需要重新创建Retrofit实例,而是在每次请求时通过拦截器替换Base URL,更适合实时切换场景。

步骤1:创建服务器URL管理器

先实现一个类来存储和管理当前选中的Base URL,比如用SharedPreferences:

class ServerUrlManager(private val context: Context) {
    private val prefs = context.getSharedPreferences("server_config", Context.MODE_PRIVATE)
    private val DEFAULT_URL = "https://default-server.example.com/"

    fun getCurrentBaseUrl(): String {
        return prefs.getString("current_base_url", DEFAULT_URL) ?: DEFAULT_URL
    }

    fun setCurrentBaseUrl(newUrl: String) {
        prefs.edit().putString("current_base_url", newUrl).apply()
    }
}

步骤2:在Koin中注入URL管理器

修改createMainModule,添加这个管理器的注入:

fun createMainModule(context: Context) = module { 
    single(named(APP_CONTEXT)) { context } 
    single(named(RESOURCES)) { context.resources } 
    single(named(SERVER_URL_MANAGER)) { ServerUrlManager(get(named(APP_CONTEXT))) }
    single(named(REPOSITORY)) { Repository(get(named(RETROFIT))) } 
}

步骤3:添加Base URL拦截器

创建一个OkHttp拦截器,在请求时替换为当前选中的Base URL:

fun createBaseUrlInterceptor(serverUrlManager: ServerUrlManager): Interceptor {
    return Interceptor { chain ->
        val originalRequest = chain.request()
        val currentBaseUrl = serverUrlManager.getCurrentBaseUrl()
        
        // 解析当前Base URL的scheme、host和路径前缀
        val baseUrlHttpUrl = HttpUrl.parse(currentBaseUrl) ?: originalRequest.url
        val newUrl = originalRequest.url.newBuilder()
            .scheme(baseUrlHttpUrl.scheme())
            .host(baseUrlHttpUrl.host())
            .port(baseUrlHttpUrl.port())
            .encodedPath(baseUrlHttpUrl.encodedPath() + originalRequest.url.encodedPath())
            .build()
        
        // 构建新的请求并继续执行
        val newRequest = originalRequest.newBuilder().url(newUrl).build()
        chain.proceed(newRequest)
    }
}

步骤4:修改NetworkModule配置

更新createNetworkModule,移除baseUrl参数,添加拦截器并注入URL管理器:

fun createNetworkModule() = module(override = true) { 
    single(named(TOKEN_INTERCEPTOR)) { createTokenInterceptor(get(named(DATA_PROVIDER))) } 
    single(named(BASE_URL_INTERCEPTOR)) { createBaseUrlInterceptor(get(named(SERVER_URL_MANAGER))) }
    single(named(OK_HTTP)) { createOkHttpClient(
        get(named(TOKEN_INTERCEPTOR)),
        get(named(BASE_URL_INTERCEPTOR))
    ) } 
    single(named(GSON)) { createGson() } 
    single(named(RETROFIT)) { createRetrofit( 
        get(named(RESOURCES)), 
        get(named(LOG_OUT_SUBJECT)), 
        get(named(GSON)), 
        "https://placeholder.example.com/", // 这里用占位URL即可,拦截器会替换
        get(named(OK_HTTP)) 
    ) }
}

步骤5:用户选择服务器后更新URL

当用户选中新服务器时,调用ServerUrlManager的方法更新URL,后续请求会自动使用新地址:

val serverUrlManager = getKoin().get<ServerUrlManager>(named(SERVER_URL_MANAGER))
serverUrlManager.setCurrentBaseUrl("https://new-selected-server.example.com/")

方案对比

  • 方案一:适合需要完全重置网络层配置的场景(比如切换服务器后需要更新拦截器逻辑),但需要重新初始化网络实例,开销稍大。
  • 方案二:轻量实时,无需重新创建Retrofit,适合频繁切换服务器的场景,仅在请求时动态替换URL。

内容的提问来源于stack exchange,提问作者ilia khuzhakhmetov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:15:28