如何为Foreground Service和Fragment实现单例Repository
问题描述
我有一个构造方法需传入Context参数的Repository(context: Context)类,该类必须为单例。常规场景下单例实现十分简单,但我的应用中存在一个即使应用从最近任务列表被移除后仍会持续运行的Foreground Service,我需要同时在该Foreground Service以及应用内其他Fragment中使用同一个Repository实例。
请问实现Repository单例的最佳方案是什么?
目前我使用dagger-hilt在Service类中注入Repository,但不确定该实现方式是否正确,以下是现有代码:
现有代码
MainApplication.kt
@HiltAndroidApp class MainApplication: Application() {}
HiltModule.kt
@Module @InstallIn(SingletonComponent::class) object HiltModule { @Singleton @Provides fun getDataStore(@ApplicationContext mContext: Context) = Repository(mContext) }
ForegroundService.kt
@AndroidEntryPoint class ForegroundService : Service() { @Inject lateinit var dataRepo: Repository }
解答
你当前的Hilt实现是完全正确的,已经满足跨组件共享单例Repository的需求,不需要做额外修改,核心原因如下:
SingletonComponent的生命周期和应用进程完全绑定。前台服务存活时,系统不会主动杀死应用进程,即使用户把应用从最近任务列表移除,只要前台服务未停止,进程就会持续存活,该作用域下生成的Repository实例全程只会存在一份。不管是在Fragment、Activity还是当前前台Service中注入,拿到的都是同一个实例。- 提供Repository实例时使用了
@ApplicationContext限定符,传入的是Application级别的全局Context,不存在短生命周期Context泄漏的问题,完全符合单例类持有Context的编码规范。
后续使用注意事项:
- 不要将Repository的作用域修改为
ServiceComponent、FragmentComponent等短生命周期作用域,否则不同组件注入时会生成独立的Repository实例,不符合单例要求。 - 在Fragment中注入Repository时,只需要给对应Fragment加上
@AndroidEntryPoint注解,使用和Service中完全一致的@Inject注入写法即可,拿到的实例和前台Service中的实例完全相同。 - 不需要额外做手动单例的兜底逻辑,Hilt的
Singleton作用域本身已经保证了进程内单例的唯一性,手动实现反而容易出现多线程同步、Context泄漏等问题。
内容的提问来源于stack exchange,提问作者Junior
相关产品推荐
相关产品推荐

