如何让子Fragment通过@Inject获取父Fragment创建的同一Service实例?
问题
在父Fragment中手动实例化了SomeService,通过childFragmentManager添加子Fragment后,希望子Fragment能通过@Inject注入父Fragment创建的同一个SomeService实例。
父Fragment代码:
@AndroidEntrypoint class ParentFragment : Hilt_ParentFragment { var service: SomeService = SomeService(/* ... */) // ... childFragmentManager.commit { add(R.id.container, ChildFragment()) } }
子Fragment代码:
@AndroidEntrypoint class ChildFragment : Hilt_ChildFragment { @Inject lateinit var service: SomeService }
解决方案
要实现子Fragment注入父Fragment持有的同一个SomeService实例,需要借助Hilt的自定义组件作用域和模块提供实例的方式,步骤如下:
1. 定义Fragment级别的自定义作用域
创建自定义注解,标记该作用域为父Fragment及其子Fragment共享的范围:
@Scope @Retention(AnnotationRetention.RUNTIME) annotation class ParentFragmentScope
2. 创建Hilt模块提供SomeService实例
编写模块,在父Fragment的组件中提供SomeService实例,并绑定到自定义作用域:
@Module @InstallIn(FragmentComponent::class) class ParentServiceModule { @Provides @ParentFragmentScope fun provideSomeService(): SomeService { return SomeService(/* ... */) } }
若
SomeService构造需要其他依赖,可直接在@Provides方法的参数中注入后传入。
3. 修改父Fragment代码,改用依赖注入
父Fragment不再手动创建SomeService,改为通过@Inject获取,并添加自定义作用域注解:
@AndroidEntrypoint @ParentFragmentScope class ParentFragment : Hilt_ParentFragment { @Inject lateinit var service: SomeService // ... childFragmentManager.commit { add(R.id.container, ChildFragment()) } }
4. 子Fragment保持原有代码即可
子Fragment的@Inject会自动从父Fragment所在的FragmentComponent中获取同一作用域的SomeService实例,无需额外修改:
@AndroidEntrypoint class ChildFragment : Hilt_ChildFragment { @Inject lateinit var service: SomeService }
原理说明
Hilt默认每个Fragment都有独立的FragmentComponent,但通过@ParentFragmentScope自定义作用域,可让父Fragment组件提供的实例在自身和所有子Fragment中共享——子Fragment的组件会继承父Fragment组件的作用域实例,从而保证注入的是同一个对象。
内容的提问来源于stack exchange,提问作者Zack R
相关产品推荐
相关产品推荐

