匕首:访问项目在子组件中创建了两个级别
Posted
技术标签:
【中文标题】匕首:访问项目在子组件中创建了两个级别【英文标题】:Dagger: Accessing item created two levels deep in a subcomponent 【发布时间】:2022-01-09 11:38:34 【问题描述】:我有一个子组件需要从中取出一些东西:
@Subcomponent(modules = SubModule.class)
@SubScope
public interface SubComp
// ...
Thing getThing();
每次调用#getThing
,我都需要一个Thing
的新实例。
Thing
也有自己的需要用它创建的项目的轨道。自然,我的直觉是为它创建另一个子组件:
@Subcomponent(modules = ModuleThing.class)
@ThingScope
public interface SubCompThing
// ...
但这是我的两难选择:哪段代码实际上应该创建Thing
?
如果我将提供程序放入SubModule
,然后我需要将该实例绑定到SubCompThing
,但我收到有关绑定多个实例的警告。该警告在我的构建中是致命的,实际上表明该警告将来会变成错误:
@Module(subcomponents = SubCompThing.class)
interface SubModule
@Provides
static providesThing(SubCompThing.Factory thingCompFactory)
Thing thing = new Thing();
thingComp = thingCompFactory.create(thing); // Warning about duplicate binding.
// Do some stuff with thingComp
return thing;
如果我有 SubCompThing
直接创建 Thing
本身,我的警告会变成具有相同问题的错误:
@Module
interface ModuleThing
@Provides
@ThingScope
static Thing providesThing()
return new Thing();
@Module(subcomponents = SubCompThing.class)
interface SubModule
@Provides
static Thing providesThing(SubCompThing.Factory thingCompFactory)
thingComp = thingCompFactory.create();
// Do some stuff with thingComp
return thingComp.getThing();
(Dagger 编译 Thing
绑定了两次,因为它有两个提供程序。)
我怎样才能让我的***SubComp
按需返回新的Thing
s,并让每个Thing
s 都有自己的子组件实例与之关联?
【问题讨论】:
您所描述的内容与 Dagger 在subcomponents for encapsulation 上的官方文档非常接近。你的名字让人有点难以理解;我是否正确理解根组件(不存在)包括引用 SubComp(@SubScope,显示)的模块(不存在),然后 SubComp 安装 SubModule(显示),它引用 SubCompThing(@ThingScope,显示),它安装 ModuleThing ,它实际上实例化了一个 @ThingScope 事物,对吧?使用 @SubScope 注释 SubModule.providesThing 是否有帮助? 是的,您已经掌握了要点。SubComp
位于某个父组件内部。 SubModule#providesThing
没有 用范围注释,因为我需要多个 Thing
s 超出 SubComp
。
【参考方案1】:
您将需要使用qualifier annotation。
这里问题的根源是子组件从其父组件继承绑定,因此在您最深的子组件 SubCompThing 中,您暴露在组件上的 Thing 绑定很可能会注入您在 SubComp 的 SubModule 中安装的 Thing 绑定。 .因为Dagger不知道你在SubModule中的@Provides方法本身就要调用SubCompThing的getThing()
方法!
正如我们在 cmets 中所讨论的,您所描述的内容非常类似于 Dagger 在 subcomponents for encapsulation 上的官方文档,它偷偷地描述但没有描述它对限定符注释的依赖:
@Subcomponent(modules = DatabaseImplModule.class)
interface DatabaseComponent
@PrivateToDatabase Database database();
/* ^^^^^^^^^^^^ */
这就是消除歧义的技巧:您的 ModuleThing 应该绑定 @Provides static @PrivateThing Thing
,而您的 SubCompThing 应该公开 @PrivateThing Thing getThing()
,以便唯一绑定的不合格事物绑定在您的 SubModule 中。 (顺便说一句,这将允许您在 SubCompThing 中注入一个事物,委托给 SubModule 的实现以从 ModuleThing 的调用堆栈中创建一个全新的 SubCompThing 实例。)
我在这里定义了一个廉价的限定符注释,但欢迎您使用@Named 对其进行原型设计。
@Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface PrivateThing
@Module
interface ModuleThing
@Provides
@ThingScope
@PrivateThing
static Thing providesThing()
return new Thing();
@Subcomponent(modules = ModuleThing.class)
@ThingScope
public interface SubCompThing
@PrivateThing getThing();
此时,您的 SubModule 无需额外修改即可工作,将 Thing 的创建抽象为 SubCompThing 的黑盒实现(我稍微喜欢这样,这样您就不必将 Thing 的实例化细节带入 SubModule )。这也意味着您可以保持 Thing 无范围,以便您可以实例化多个它们:当您调用提供者时,您会看到一些新的东西。 That way you can make both thing1
and thing2
.
【讨论】:
以上是关于匕首:访问项目在子组件中创建了两个级别的主要内容,如果未能解决你的问题,请参考以下文章
django makemigration 在子应用程序上抛出错误