如何在Hilt单例模块中为OkHttp拦截器获取LifecycleOwner?
解决Hilt中OkHttp拦截器获取LifecycleOwner的问题
问题核心
OkHttpClient属于单例作用域(SingletonComponent),而LifecycleOwner(如Activity、Fragment)是页面级作用域,生命周期远短于单例。直接在单例拦截器中注入LifecycleOwner会触发Hilt作用域不匹配的错误,还可能导致内存泄漏。
解决方案:通过动态持有类中转
1. 创建单例的Lifecycle持有者类
用来临时存储当前活跃的LifecycleOwner:
class LifecycleHolder @Inject constructor() { @Volatile var currentLifecycleOwner: LifecycleOwner? = null }
2. 修改拦截器,依赖LifecycleHolder
不再直接持有LifecycleOwner,而是通过持有者动态获取:
class MyInterceptor @Inject constructor( private val lifecycleHolder: LifecycleHolder ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response { val currentOwner = lifecycleHolder.currentLifecycleOwner // 使用时必须判空,避免无活跃页面时出现空指针 currentOwner?.let { owner -> // 示例:监听生命周期事件 owner.lifecycle.addObserver(object : LifecycleEventObserver { override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { // 处理逻辑 // 记得用完移除观察者,防止内存泄漏 source.lifecycle.removeObserver(this) } }) } return chain.proceed(chain.request()) } }
3. 调整Hilt模块配置
让Hilt管理LifecycleHolder和拦截器的依赖,确保都是单例:
@Module @InstallIn(SingletonComponent::class) object AppEntryModule { @Provides @Singleton fun provideLifecycleHolder(): LifecycleHolder = LifecycleHolder() @Provides @Singleton fun provideMyInterceptor(lifecycleHolder: LifecycleHolder): MyInterceptor = MyInterceptor(lifecycleHolder) @Provides @Singleton fun provideOkHttpClient(interceptor: MyInterceptor): OkHttpClient = OkHttpClient.Builder() .addInterceptor(interceptor) .build() @Provides @Singleton fun provideRetrofit(client: OkHttpClient): Retrofit = Retrofit.Builder() .baseUrl(MOCK_URL) .client(client) .addConverterFactory(GsonConverterFactory.create()) .build() }
4. 在页面中动态更新LifecycleOwner
在BaseActivity或BaseFragment的生命周期方法中,更新持有者的当前LifecycleOwner:
abstract class BaseActivity : AppCompatActivity() { @Inject lateinit var lifecycleHolder: LifecycleHolder override fun onResume() { super.onResume() // 页面活跃时设置当前Activity为LifecycleOwner lifecycleHolder.currentLifecycleOwner = this } override fun onPause() { super.onPause() // 页面失活时清空,避免持有已销毁的Activity引用 lifecycleHolder.currentLifecycleOwner = null } }
如果是Fragment,推荐使用viewLifecycleOwner更安全:
abstract class BaseFragment : Fragment() { @Inject lateinit var lifecycleHolder: LifecycleHolder override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewLifecycleOwner.lifecycle.addObserver(object : LifecycleEventObserver { override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { when(event) { Lifecycle.Event.ON_RESUME -> { lifecycleHolder.currentLifecycleOwner = source } Lifecycle.Event.ON_PAUSE -> { lifecycleHolder.currentLifecycleOwner = null } else -> {} } } }) } }
注意事项
- 必须在页面失活时清空LifecycleHolder的引用,防止内存泄漏。
- 拦截器中使用LifecycleOwner前一定要判空,避免App在后台发起请求时出现空指针。
内容的提问来源于stack exchange,提问作者Dmitry Sergienko
相关产品推荐
相关产品推荐

