使用子组件封装时无限递归
Infinite recursion when using subcomponent for encapsulation
我试图通过使用 here 描述的子组件来实现封装,但我得到了无限递归。
这是我的代码:
//tried adding @ScopeA, still the same.
public class A {
@Inject
A(B b) {
}
}
@ScopeA
public class B {
@Inject
B() {
}
}
@Component(modules = AModule.class)
@Singleton
public interface AComponent {
public A a();
}
@Module(subcomponents = SComponent.class)
class AModule {
@Provides
@Singleton
A a(SComponent.Factory factory) {
return factory.component().a();
}
}
@Subcomponent
@ScopeA
interface SComponent {
@ScopeA
A a();
@Subcomponent.Factory
interface Factory {
SComponent component();
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAComponent.create().a();
}
}
检查生成的匕首代码后,我发现:
private final class SComponentImpl implements SComponent {
private SComponentImpl() {}
@Override
public A a() {
return DaggerAComponent.this.aProvider.get();
}
}
似乎SComponent正在从父组件获取A
,这不是我想要的,我的代码问题在哪里?
请注意,封装子组件页面中的示例使用了 qualifier annotation、@PrivateToDatabase
,这不是作用域注释,它将 Database
的绑定与 Database
的绑定区分开来@PrivateToDatabase Database
.
子组件从它们的父组件继承所有绑定,因此您当前可以从父组件获得 A,也可以从子组件获得 A。如果你的子组件中有任何东西需要注入 A,如果它没有被标记 @Singleton
: 你想要来自父组件的 A,还是来自子组件的 A,这尤其棘手?
这种情况的另一个棘手部分是您不能在使用 @Inject
构造函数的 类 上使用限定符注释。
我建议您执行以下操作:
- 从A中提取一个接口,这样你就有了A和AImpl。
- 保留从子组件获取 A 实例的
@Provides
方法。
- 让子组件公开 AImpl,并且(为了最好地避免歧义)只在子组件的 类 中注入 AImpl,而不是 A.
如果您不想提取接口,也可以通过从 A 中删除 @Inject
并在 [=37] 的子组件中的模块中编写 @Provides
方法来解决此问题=]一个合格的A,所以不合格的A走顶层组件,合格的A只在子组件内部可用。
我试图通过使用 here 描述的子组件来实现封装,但我得到了无限递归。
这是我的代码:
//tried adding @ScopeA, still the same.
public class A {
@Inject
A(B b) {
}
}
@ScopeA
public class B {
@Inject
B() {
}
}
@Component(modules = AModule.class)
@Singleton
public interface AComponent {
public A a();
}
@Module(subcomponents = SComponent.class)
class AModule {
@Provides
@Singleton
A a(SComponent.Factory factory) {
return factory.component().a();
}
}
@Subcomponent
@ScopeA
interface SComponent {
@ScopeA
A a();
@Subcomponent.Factory
interface Factory {
SComponent component();
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DaggerAComponent.create().a();
}
}
检查生成的匕首代码后,我发现:
private final class SComponentImpl implements SComponent {
private SComponentImpl() {}
@Override
public A a() {
return DaggerAComponent.this.aProvider.get();
}
}
似乎SComponent正在从父组件获取A
,这不是我想要的,我的代码问题在哪里?
请注意,封装子组件页面中的示例使用了 qualifier annotation、@PrivateToDatabase
,这不是作用域注释,它将 Database
的绑定与 Database
的绑定区分开来@PrivateToDatabase Database
.
子组件从它们的父组件继承所有绑定,因此您当前可以从父组件获得 A,也可以从子组件获得 A。如果你的子组件中有任何东西需要注入 A,如果它没有被标记 @Singleton
: 你想要来自父组件的 A,还是来自子组件的 A,这尤其棘手?
这种情况的另一个棘手部分是您不能在使用 @Inject
构造函数的 类 上使用限定符注释。
我建议您执行以下操作:
- 从A中提取一个接口,这样你就有了A和AImpl。
- 保留从子组件获取 A 实例的
@Provides
方法。 - 让子组件公开 AImpl,并且(为了最好地避免歧义)只在子组件的 类 中注入 AImpl,而不是 A.
如果您不想提取接口,也可以通过从 A 中删除 @Inject
并在 [=37] 的子组件中的模块中编写 @Provides
方法来解决此问题=]一个合格的A,所以不合格的A走顶层组件,合格的A只在子组件内部可用。