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

使用Hilt时如何运行时配置OkHttp代理?Hilt支持模块重初始化吗?

问题解答

一、运行时动态创建带/不带代理的Retrofit实例

你的需求是在App运行过程中根据条件切换代理配置,而Hilt默认的单例绑定无法满足动态变化的需求——单例实例在组件初始化时就已创建并固定。可以通过工厂模式+代理状态管理来实现:

1. 全局管理代理状态

先创建一个单例类保存当前代理的启用状态和配置,方便随时修改和读取:

class ProxyManager private constructor() {
    var isProxyEnabled: Boolean = false
        private set
    var proxyHost: String = "localhost"
        private set
    var proxyPort: Int = 8080
        private set

    // 更新代理配置
    fun updateProxyConfig(enabled: Boolean, host: String = "localhost", port: Int = 8080) {
        isProxyEnabled = enabled
        proxyHost = host
        proxyPort = port
    }

    companion object {
        val INSTANCE: ProxyManager by lazy(LazyThreadSafetyMode.SYNCHRONIZED) {
            ProxyManager()
        }
    }
}

2. 修改Hilt模块,引入工厂类生成动态实例

去掉OkHttpClient和Retrofit的@Singleton注解,改用工厂类根据当前代理状态生成对应实例:

@Module
@InstallIn(SingletonComponent::class)
class NetworkModule {
    private val TIMEOUT_UNIT = TimeUnit.MILLISECONDS
    private val TIMEOUT_MILLIS: Long = 10000

    // 提供ProxyManager单例
    @Singleton
    @Provides
    fun provideProxyManager(): ProxyManager = ProxyManager.INSTANCE

    // 通过Retrofit工厂获取ApiService,保证每次使用的是最新配置的实例
    @Provides
    fun provideApi(retrofitFactory: RetrofitFactory): ApiService =
        retrofitFactory.getRetrofit().create(ApiService::class.java)

    // 提供Retrofit工厂
    @Singleton
    @Provides
    fun provideRetrofitFactory(
        okHttpClientFactory: OkHttpClientFactory,
        converter: Converter.Factory
    ): RetrofitFactory = RetrofitFactory(okHttpClientFactory, converter)

    // 提供OkHttpClient工厂
    @Singleton
    @Provides
    fun provideOkHttpClientFactory(
        loggingInterceptor: HttpLoggingInterceptor,
        proxyManager: ProxyManager
    ): OkHttpClientFactory = OkHttpClientFactory(loggingInterceptor, proxyManager)

    @Provides
    fun provideHttpLoggingInterceptor(): HttpLoggingInterceptor {
        val loggingInterceptor = HttpLoggingInterceptor()
        loggingInterceptor.level = if (BuildConfig.DEBUG) {
            HttpLoggingInterceptor.Level.BODY
        } else {
            HttpLoggingInterceptor.Level.NONE
        }
        return loggingInterceptor
    }

    @Provides
    fun provideConverterFactory(gson: Gson): Converter.Factory {
        return GsonConverterFactory.create(gson)
    }

    @Provides
    fun providesGson(): Gson = Gson()
}

// OkHttpClient工厂,根据当前代理状态生成客户端
class OkHttpClientFactory(
    private val loggingInterceptor: HttpLoggingInterceptor,
    private val proxyManager: ProxyManager
) {
    fun createOkHttpClient(): OkHttpClient {
        val builder = OkHttpClient.Builder()
            .retryOnConnectionFailure(true)
            .connectTimeout(3 * TIMEOUT_MILLIS, TIMEOUT_UNIT)
            .readTimeout(6 * TIMEOUT_MILLIS, TIMEOUT_UNIT)
            .writeTimeout(12 * TIMEOUT_MILLIS, TIMEOUT_UNIT)
            .addInterceptor(loggingInterceptor)

        // 根据当前状态添加代理
        if (proxyManager.isProxyEnabled) {
            val proxy = Proxy(
                Proxy.Type.HTTP,
                InetSocketAddress.createUnresolved(proxyManager.proxyHost, proxyManager.proxyPort)
            )
            builder.proxy(proxy)
        }

        return builder.build()
    }

    companion object {
        private val TIMEOUT_UNIT = TimeUnit.MILLISECONDS
        private val TIMEOUT_MILLIS: Long = 10000
    }
}

// Retrofit工厂,生成对应配置的Retrofit实例
class RetrofitFactory(
    private val okHttpClientFactory: OkHttpClientFactory,
    private val converterFactory: Converter.Factory
) {
    fun getRetrofit(): Retrofit = Retrofit.Builder()
        .baseUrl(BuildConfig.BASE_URL)
        .client(okHttpClientFactory.createOkHttpClient())
        .addConverterFactory(converterFactory)
        .build()
}

3. 运行时切换代理

在需要修改代理的地方,直接调用ProxyManager的更新方法即可,后续获取的ApiService会自动使用新的代理配置:

// 启用代理
ProxyManager.INSTANCE.updateProxyConfig(enabled = true, host = "192.168.1.100", port = 8888)
// 禁用代理
ProxyManager.INSTANCE.updateProxyConfig(enabled = false)

注意:如果你的ApiService被注入为单例,会持有第一次创建的Retrofit实例。这种情况下,建议每次发起请求前都通过RetrofitFactory获取最新的Retrofit来创建ApiService,或者让ApiService内部持有RetrofitFactory,每次请求时使用最新实例。

二、Hilt是否支持类似Koin的unloadModule功能?

不支持。Hilt是基于编译时注解生成代码的DI框架,模块的绑定关系在编译阶段就已确定,且绑定到对应的组件生命周期(比如SingletonComponent在App启动时初始化)。一旦组件初始化完成,模块的绑定就固定了,无法动态卸载或重新初始化模块。

如果需要类似动态更新依赖的功能,只能通过自己管理实例(比如上述的工厂模式),或者结合@EntryPoint手动获取新实例,但本质上都是自己处理动态创建逻辑,而非模块的重新加载。

内容的提问来源于stack exchange,提问作者Aldrin Joe Mathew

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 00:10:14