使用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
相关产品推荐
相关产品推荐

