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

使用Hilt-Android时单例依赖注入的疑问

关于Hilt中Retrofit依赖链@Singleton注解的疑问解答

你的做法不是错误,但存在潜在隐患,下面具体拆解原因:

1. 为什么移除下层依赖的@Singleton后hashcode不变?

因为你给Retrofit加了@Singleton,Hilt在创建这个单例Retrofit实例时,会一次性构建它依赖的所有对象(OkHttpClient、Interceptor),这些对象会被Retrofit实例持有。只要Retrofit的单例实例不被销毁(应用生命周期内@Singleton的对象不会被销毁),这些下层依赖就会一直被持有,自然不会被重建,hashcode也就不会变。

但要注意:这是被动的单例状态,是上层对象持有导致的,并非Hilt主动保证的单例。

2. 为什么官方/参考示例都给每个@Provides方法加@Singleton?

  • 明确生命周期语义:@Singleton是给Hilt和其他开发者明确信号——这个对象要在整个应用生命周期只创建一次。如果后续项目迭代中,有其他地方需要依赖这个Interceptor或OkHttpClient(比如新增另一个Retrofit实例、或者某个工具类需要直接用OkHttpClient),没加@Singleton的话,Hilt会为新的依赖请求创建全新的实例,导致多个实例共存,可能出现日志不一致、缓存不共享、拦截器逻辑重复执行等问题。
  • 避免意外重建:虽然@Singleton的Retrofit不会被销毁,但如果是其他scope的上层对象(比如ActivityRetainedComponent级别的对象),下层依赖没加对应scope注解的话,可能会随着上层对象的重建而被重新创建。用@Singleton绑定应用级生命周期,能彻底避免这类意外。
  • 团队协作清晰:注解是代码的“自我说明”,加@Singleton能让团队成员一眼就知道这个对象是全局复用的,不会误用导致不必要的多实例问题。

3. 什么时候可以只给上层加@Singleton?

只有一种极端情况:这些下层依赖永远只会被这个单例上层对象依赖,绝对不会有其他消费者。但实际项目中这种场景极少,需求迭代很容易打破这个假设,所以不建议这么做。

代码示例对比

不推荐的写法(仅上层加@Singleton)

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    fun provideRequestInterceptor(): RequestInterceptor {
        return RequestInterceptor()
    }

    @Provides
    fun provideOkHttpClient(interceptor: RequestInterceptor): OkHttpClient {
        return OkHttpClient.Builder().addInterceptor(interceptor).build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(client: OkHttpClient): Retrofit {
        return Retrofit.Builder().client(client).baseUrl("https://example.com").build()
    }
}

后续新增依赖时会创建新实例:

// 新增的工具类,会得到全新的OkHttpClient实例
@Provides
fun provideNetworkUtil(client: OkHttpClient): NetworkUtil {
    return NetworkUtil(client)
}

推荐的写法(全链路加@Singleton)

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    @Singleton
    fun provideRequestInterceptor(): RequestInterceptor {
        return RequestInterceptor()
    }

    @Provides
    @Singleton
    fun provideOkHttpClient(interceptor: RequestInterceptor): OkHttpClient {
        return OkHttpClient.Builder().addInterceptor(interceptor).build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(client: OkHttpClient): Retrofit {
        return Retrofit.Builder().client(client).baseUrl("https://example.com").build()
    }
}

无论哪里依赖,都能拿到同一个实例,避免潜在问题。


内容的提问来源于stack exchange,提问作者JungHoon

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 23:25:22