考虑一组MVP类型的类型。存在一个抽象的Presenter,带有View界面:
public interface View {
//...
}
public abstract class AbstractPresenter<V extends View> {
@Inject V view;
//...
}
然后,让我们有一个特定的具体presenter子类,并带有其 View 接口(interface)和实现:
public interface LoginView extends View {
//...
}
public LoginPresenter extends AbstractPresenter<LoginView> {
//...
}
public class LoginViewImpl implements LoginView {
//...
}
在Dagger模块中,我们当然会定义一个
@Provides
方法:@Provides
LoginView provideLoginView() {
return new LoginViewImpl();
}
在Guice中,您可以用相同的方式编写,或者只是
bind(LoginView.class).to(LoginViewImpl.class)
。但是,在Dagger(v1和来自Google的2.0-SNAPSHOT)中,这会产生错误,因为在为
V
创建绑定(bind)连线时无法弄清楚AbstractPresenter<V>
是什么。另一方面,Guice指出这是因为它实际上是在创建LoginPresenter
,因此它需要实现LoginView
。Dagger 1.2.2:
foo.bar.AbstractPresenter$$InjectAdapter.java:[21,31] cannot find symbol
symbol: class V
location: class foo.bar.AbstractPresenter$$InjectAdapter
Dagger 2.0版快照:
Caused by: java.lang.IllegalArgumentException: V
at dagger.internal.codegen.writer.TypeNames$2.defaultAction(TypeNames.java:39)
at dagger.internal.codegen.writer.TypeNames$2.defaultAction(TypeNames.java:36)
at javax.lang.model.util.SimpleTypeVisitor6.visitTypeVariable(SimpleTypeVisitor6.java:179)
at com.sun.tools.javac.code.Type$TypeVar.accept(Type.java:1052)
at dagger.internal.codegen.writer.TypeNames.forTypeMirror(TypeNames.java:36)
at dagger.internal.codegen.MembersInjectorGenerator.write(MembersInjectorGenerator.java:142)
at dagger.internal.codegen.MembersInjectorGenerator.write(MembersInjectorGenerator.java:61)
at dagger.internal.codegen.SourceFileGenerator.generate(SourceFileGenerator.java:53)
at dagger.internal.codegen.InjectBindingRegistry.generateSourcesForRequiredBindings(InjectBindingRegistry.java:101)
at dagger.internal.codegen.ComponentProcessor.process(ComponentProcessor.java:149)
我的问题:这是一个错误吗?这是缺少的功能吗?还是这是Dagger保护我们免受其影响的性能问题(GWT RPC中的SerializableTypeOracleBuilder)?
请注意,当
V
称为Provider<V>
,Lazy<V>
等时,也会发生相同的问题。 最佳答案
这看起来像一个错误,因为它不应该引发异常,但是应该记录一条警告,说明类型参数需要绑定(bind)到特定类型。
其余的用于Dagger2,我使用的是2.1-SNAPSHOT。您尚未提供将进行注入(inject)的@Component
示例,没有它,Dagger2 2.1-SNAPSHOT实际上不会报告问题。可能它已经解决了您的问题,并且我看到的版本略有不同,但是如果没有,我认为您的组件看起来像这样:
@Component
public interface PresenterComponent {
<V extends View> void inject(AbstractPresenter<V> presenter);
}
在Dagger2处理此代码时,它无法确定
V
的具体类型,因此它不知道要插入哪种类型。它不能只插入说LoginView
,因为如果传递了AbstractPresenter<LogoutView>
,那会中断。但是,如果使用以下命令,则Dagger2可以确定需要将LoginView注入(inject)
AbstractPresenter<LoginView>
中,并且将这样做安全。@Module
public class LoginModule {
@Provides LoginView provideLoginView() {
return new LoginViewImpl();
}
}
@Component(modules = LoginModule.class)
public interface LoginComponent {
void inject(LoginPresenter presenter);
}
除非您无法控制何时创建对象,例如如果某个框架为您创建了它然后传递给您进行初始化,那么如果可以的话,最好在构造函数上使用
@Inject
,例如像这样:public LoginPresenter extends AbstractPresenter<LoginView> {
//...
@Inject LoginPresenter(LoginView view) {
super(view);
//...
}
}