Dagger Hilt中单例提供的OkHttp如何更新OAuth拦截器的授权凭证
问题根因
你当前的实现是在构造OauthInterceptor实例时就一次性读取了OauthManager中的凭证值,相当于把应用启动时(未登录状态)的凭证做了静态快照存入拦截器。而标注了@Singleton的OkHttpClient实例全局只会初始化一次,后续你更新SharedPreferences里的凭证后,已经初始化完成的拦截器不会主动读取新值,自然无法生效。
最优解决方案:拦截器内动态读取凭证
不需要修改OkHttpClient的单例作用域,也不需要重新创建OkHttpClient实例,只需要调整拦截器的实现逻辑:将凭证读取操作放到每次请求拦截时执行,而非构造拦截器时执行,具体实现如下:
步骤1:调整OauthInterceptor构造逻辑
去掉构造方法中传入的accessToken/accessSecret/verifier三个参数,改为直接传入OauthManager实例:
class OauthInterceptor( private val consumerKey: String, private val consumerSecret: String, private val oauthManager: OauthManager ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { // 每次请求都读取最新的凭证 val accessToken = oauthManager.getToken() val accessSecret = oauthManager.getSecret() val verifier = oauthManager.getVerifier() // 原有签名、添加请求头逻辑不变 // ... return chain.proceed(originalRequest) } }
步骤2:调整Hilt依赖注入配置
首先将OauthManager配置为单例注入,避免每次都初始化SP实例:
@Singleton @Provides fun provideOauthManager(@ApplicationContext context: Context): OauthManager { return OauthManager(context) // 替换为你实际的OauthManager初始化逻辑 }
再修改OkHttpClient的提供方法,直接注入OauthManager实例传给拦截器即可:
@Singleton @Provides @Named(NAME_WITH_OAUTH) fun provideOkHttp( oauthManager: OauthManager ) = OkHttpClient .Builder() .addInterceptor( OauthInterceptor( consumerKey = Constants.CONSUMER_KEY, consumerSecret = Constants.CONSUMER_SECRET, oauthManager = oauthManager ) ) // 可按需添加连接池、超时等配置 .build()
方案优势
- 保留OkHttpClient的单例特性,复用连接池、缓存等配置,性能损耗最低
- 登录成功后更新SharedPreferences的凭证后,无需额外操作,后续请求自动携带最新凭证
- 实现逻辑简单,不需要额外维护作用域、实例刷新逻辑
可选备选方案(不推荐)
如果确实不能修改拦截器的构造逻辑,可以通过自定义作用域在登录完成后重新创建OkHttpClient实例,但该方案会销毁原有连接池,产生额外性能开销,仅作为极端场景下的备选。
内容的提问来源于stack exchange,提问作者SomeKoder
相关产品推荐
相关产品推荐

