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

Android Kotlin如何点击按钮动态切换Retrofit的BASE_URL?

运行时动态切换Retrofit BASE_URL的实现方案

核心问题根源

Hilt默认提供的Retrofit实例是单例,初始化时就绑定了固定BASE_URL,后续无法直接修改。要实现运行时切换,核心是让请求的BaseUrl可动态替换,同时调整Hilt的依赖提供逻辑适配这种动态性。

具体修改步骤

1. 实现动态BaseUrl拦截器

创建OkHttp拦截器,用于在请求发起时替换BaseUrl,并支持运行时更新:

class DynamicBaseUrlInterceptor(private var baseUrl: String) : Interceptor {
    @Synchronized
    fun updateBaseUrl(newUrl: String) {
        this.baseUrl = newUrl
    }

    override fun intercept(chain: Interceptor.Chain): Response {
        val originalRequest = chain.request()
        // 替换原始请求的BaseUrl,保留路径参数
        val newRequest = originalRequest.newBuilder()
            .url(baseUrl + originalRequest.url.encodedPath)
            .build()
        return chain.proceed(newRequest)
    }
}

2. 调整NetworkModule的依赖提供逻辑

修改Hilt模块,将固定BASE_URL改为从本地存储读取初始值,同时注入可动态更新的拦截器:

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

    // 提供全局唯一的动态BaseUrl拦截器
    @Provides
    @Singleton
    fun provideDynamicBaseUrlInterceptor(@ApplicationContext context: Context): DynamicBaseUrlInterceptor {
        // 从SharedPreferences读取初始BaseUrl(首次启动用默认值)
        val sp = context.getSharedPreferences("app_config", Context.MODE_PRIVATE)
        val initialUrl = sp.getString("base_url", "https://default-api.com/") ?: "https://default-api.com/"
        return DynamicBaseUrlInterceptor(initialUrl)
    }

    // 配置OkHttpClient,注入动态拦截器
    @Provides
    @Singleton
    fun provideOkHttpClient(interceptor: DynamicBaseUrlInterceptor): OkHttpClient {
        return OkHttpClient.Builder()
            .addInterceptor(interceptor)
            // 保留原有配置(日志、超时时间等)
            .build()
    }

    // 提供Retrofit实例,这里的baseUrl仅作为占位符(会被拦截器替换)
    @Provides
    @Singleton
    fun provideRetrofit(client: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://placeholder.com/") // 任意合法URL即可
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }

    // 提供ApiService,保持原有逻辑
    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

3. 封装BaseUrl管理类(可选,优化代码结构)

创建单例类统一管理BaseUrl的更新与持久化,避免直接操作拦截器:

class BaseUrlManager @Inject constructor(
    private val interceptor: DynamicBaseUrlInterceptor,
    @ApplicationContext private val context: Context
) {
    fun updateBaseUrl(newUrl: String) {
        // 持久化新URL,保证重启后生效
        val sp = context.getSharedPreferences("app_config", Context.MODE_PRIVATE)
        sp.edit().putString("base_url", newUrl).apply()
        // 更新拦截器的BaseUrl
        interceptor.updateBaseUrl(newUrl)
    }

    fun getCurrentBaseUrl(): String {
        val sp = context.getSharedPreferences("app_config", Context.MODE_PRIVATE)
        return sp.getString("base_url", "https://default-api.com/") ?: "https://default-api.com/"
    }
}

4. 在ViewModel中处理切换逻辑

通过Hilt注入BaseUrlManager,在ViewModel中封装切换方法:

@HiltViewModel
class SettingsViewModel @Inject constructor(
    private val baseUrlManager: BaseUrlManager
) : ViewModel() {

    fun switchBaseUrl(newUrl: String) {
        // 简单校验URL格式(可选)
        if (newUrl.isNotEmpty() && newUrl.startsWith("http")) {
            baseUrlManager.updateBaseUrl(newUrl)
            // 可通过LiveData通知UI切换成功
        }
    }
}

5. 按钮点击触发切换

在Activity/Fragment中绑定ViewModel,响应按钮点击事件:

@AndroidEntryPoint
class SettingsFragment : Fragment() {
    private val viewModel: SettingsViewModel by viewModels()

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        btn_switch_url.setOnClickListener {
            val newUrl = et_new_url.text.toString().trim()
            viewModel.switchBaseUrl(newUrl)
        }
    }
}

关键注意事项

  • 拦截器的updateBaseUrl方法添加@Synchronized,避免多线程更新时的竞争问题
  • Retrofit初始化的baseUrl只需填任意合法URL,实际请求会被拦截器替换为动态设置的地址
  • 如果ApiService中存在全路径请求,需在拦截器中增加判断逻辑,避免错误替换

内容的提问来源于stack exchange,提问作者Riddhish.Chaudhari

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 10:50:22