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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 23:26:05