Dagger2:注入实现 类 由组件本身的模块提供
Dagger2: Injecting implementation classes provided by modules with component itself
考虑到模块都是通过 complete=false, library=true
的 Dagger1 规范相互共享的,您可以通过构造函数参数接收 @Provides
方法提供的元素,就像这样。
public class GetUserForUsernameTaskImpl
implements GetUserForUsernameTask {
public static final String TAG = GetUserForUsernameTaskImpl.class.getSimpleName();
private Realm realm;
private UserRepository userRepository;
public GetUserForUsernameTaskImpl(Realm realm, UserRepository userRepository) {
this.realm = realm;
this.userRepository = userRepository;
}
@Override
public RealmResults<UserRLM> getUsers() {
try {
RealmResults<UserRLM> users = userRepository.findAll(realm);
...
}
@Module(includes = {RepositoryModule.class, RealmModule.class})
public class DatabaseTaskModule {
@Provides
public GetUsersDatabaseTask getUsersDatabaseTask(Realm realm, UserRepository userRepository) {
return new GetUsersDatabaseTaskImpl(realm, userRepository);
}
}
但是,您也可以仅指定一个包含组件图的依赖项(Presenter
或 CustomApplication
实例),并使用该组件图注入您的实现 类 .
public class GetUserForUsernameTaskImpl
implements GetUserForUsernameTask {
public static final String TAG = GetUserForUsernameTaskImpl.class.getSimpleName();
@Inject
public Realm realm;
@Inject
public UserRepository userRepository;
protected Presenter presenter;
private boolean isInjected = false;
public GetUserForUsernameTaskImpl(Presenter presenter) {
this.presenter = presenter;
}
@Override
public RealmResults<UserRLM> getUsers() {
if(!isInjected) {
presenter.getPresenterComponent().inject(this);
isInjected = true;
}
try {
RealmResults<UserRLM> users = userRepository.findAll(realm);
...
}
}
@Module(includes = {PresenterModule.class})
public class DatabaseTaskModule {
@Provides
public GetUsersDatabaseTask getUsersDatabaseTask(Presenter presenter) {
return new GetUsersDatabaseTaskImpl(presenter);
}
}
这样一来,您只需要依赖演示者的对象图,而不必弄乱构造函数参数。
哪种方法更好?
编辑: 我在一个不太好的重构项目中有一个更清晰具体的例子如下:
@Module(includes = {ContextModule.class})
public class ClientAuthModule {
@Provides
public ClientAuthAuthenticator clientAuthAuthenticator(CustomApplication customApplication) {
return new ClientAuthAuthenticator(customApplication);
}
}
然后
public class CustomApplication
extends Application {
public static class InjectorInitializedEvent {
}
public static class InjectorInitializedEventProducer {
@Produce
public InjectorInitializedEvent produceEvent() {
return new InjectorInitializedEvent();
}
}
private ApplicationComponent applicationComponent;
@Override
public void onCreate() {
super.onCreate();
applicationComponent = Injector.INSTANCE.initializeApplicationComponent();
SingletonBus.INSTANCE.getBus().post(new InjectorInitializedEvent());
SingletonBus.INSTANCE.getBus().register(new InjectorInitializedEventProducer()); //OTTO bus, event producer
}
public ApplicationComponent getApplicationComponent() {
return this.applicationComponent;
}
}
然后
public class ClientAuthAuthenticator {
private CustomApplication customApplication;
@Inject
public PEMConverter pemConverter;
@Inject
public KeyPairCreator keyPairCreator;
@Inject
public PKCS10CsrCreator pkcs10CsrCreator;
@Inject
public KeyPairReader keyPairReader;
//...
public ClientAuthAuthenticator(CustomApplication customApplication) {
this.customApplication = customApplication;
SingletonBus.INSTANCE.getBus().register(this);
}
@Subscribe
public void onInjectorInitializedEvent(CustomApplication.InjectorInitializedEvent e) {
customApplication.getApplicationComponent().inject(this);
SingletonBus.INSTANCE.getBus().unregister(this);
}
...
问题: 这样,当注入器准备就绪时,所有依赖项都从应用程序的组件提供,而不是通过构造函数提供。但这是一个好方法吗? long-运行有什么注意事项吗?
EDIT2:我这里有注射器,但它很糟糕。
我有一个 in my other project was better constructed。
使用构造函数注入方法,您仅使用标准 JSR-330 注释对 类 进行注释,因此:
代码与您正在使用的具体依赖注入库分离。如果你需要回到,比方说,旧版本的匕首,只有你的模块和组件定义需要改变,而不是你的核心 类.
您的 类 不需要知道它们是如何生成的细节。明天您可能会根据范围使用不同的组件,或者您可能希望将您的组件从演示者中取出 类。你的核心 类 不应该因此改变。
它使您的模块测试更容易。无需 运行 代码生成或通过您的应用程序替换组件实例。只需在构造函数中直接注入模拟或测试模块即可。
只有在模块的生命周期不受您控制的情况下,才应使用字段和方法注入。 Android 环境中的活动或片段就是这种情况。在该用例之外,这些方法只是问题的根源。
如果你的依赖是通过组件/模块提供的,那么当依赖被创建时组件将一直存在。所以你可以在它的构造函数中调用字段注入。没有比这更简单的了。
考虑到模块都是通过 complete=false, library=true
的 Dagger1 规范相互共享的,您可以通过构造函数参数接收 @Provides
方法提供的元素,就像这样。
public class GetUserForUsernameTaskImpl
implements GetUserForUsernameTask {
public static final String TAG = GetUserForUsernameTaskImpl.class.getSimpleName();
private Realm realm;
private UserRepository userRepository;
public GetUserForUsernameTaskImpl(Realm realm, UserRepository userRepository) {
this.realm = realm;
this.userRepository = userRepository;
}
@Override
public RealmResults<UserRLM> getUsers() {
try {
RealmResults<UserRLM> users = userRepository.findAll(realm);
...
}
@Module(includes = {RepositoryModule.class, RealmModule.class})
public class DatabaseTaskModule {
@Provides
public GetUsersDatabaseTask getUsersDatabaseTask(Realm realm, UserRepository userRepository) {
return new GetUsersDatabaseTaskImpl(realm, userRepository);
}
}
但是,您也可以仅指定一个包含组件图的依赖项(Presenter
或 CustomApplication
实例),并使用该组件图注入您的实现 类 .
public class GetUserForUsernameTaskImpl
implements GetUserForUsernameTask {
public static final String TAG = GetUserForUsernameTaskImpl.class.getSimpleName();
@Inject
public Realm realm;
@Inject
public UserRepository userRepository;
protected Presenter presenter;
private boolean isInjected = false;
public GetUserForUsernameTaskImpl(Presenter presenter) {
this.presenter = presenter;
}
@Override
public RealmResults<UserRLM> getUsers() {
if(!isInjected) {
presenter.getPresenterComponent().inject(this);
isInjected = true;
}
try {
RealmResults<UserRLM> users = userRepository.findAll(realm);
...
}
}
@Module(includes = {PresenterModule.class})
public class DatabaseTaskModule {
@Provides
public GetUsersDatabaseTask getUsersDatabaseTask(Presenter presenter) {
return new GetUsersDatabaseTaskImpl(presenter);
}
}
这样一来,您只需要依赖演示者的对象图,而不必弄乱构造函数参数。
哪种方法更好?
编辑: 我在一个不太好的重构项目中有一个更清晰具体的例子如下:
@Module(includes = {ContextModule.class})
public class ClientAuthModule {
@Provides
public ClientAuthAuthenticator clientAuthAuthenticator(CustomApplication customApplication) {
return new ClientAuthAuthenticator(customApplication);
}
}
然后
public class CustomApplication
extends Application {
public static class InjectorInitializedEvent {
}
public static class InjectorInitializedEventProducer {
@Produce
public InjectorInitializedEvent produceEvent() {
return new InjectorInitializedEvent();
}
}
private ApplicationComponent applicationComponent;
@Override
public void onCreate() {
super.onCreate();
applicationComponent = Injector.INSTANCE.initializeApplicationComponent();
SingletonBus.INSTANCE.getBus().post(new InjectorInitializedEvent());
SingletonBus.INSTANCE.getBus().register(new InjectorInitializedEventProducer()); //OTTO bus, event producer
}
public ApplicationComponent getApplicationComponent() {
return this.applicationComponent;
}
}
然后
public class ClientAuthAuthenticator {
private CustomApplication customApplication;
@Inject
public PEMConverter pemConverter;
@Inject
public KeyPairCreator keyPairCreator;
@Inject
public PKCS10CsrCreator pkcs10CsrCreator;
@Inject
public KeyPairReader keyPairReader;
//...
public ClientAuthAuthenticator(CustomApplication customApplication) {
this.customApplication = customApplication;
SingletonBus.INSTANCE.getBus().register(this);
}
@Subscribe
public void onInjectorInitializedEvent(CustomApplication.InjectorInitializedEvent e) {
customApplication.getApplicationComponent().inject(this);
SingletonBus.INSTANCE.getBus().unregister(this);
}
...
问题: 这样,当注入器准备就绪时,所有依赖项都从应用程序的组件提供,而不是通过构造函数提供。但这是一个好方法吗? long-运行有什么注意事项吗?
EDIT2:我这里有注射器,但它很糟糕。
我有一个 in my other project was better constructed。
使用构造函数注入方法,您仅使用标准 JSR-330 注释对 类 进行注释,因此:
代码与您正在使用的具体依赖注入库分离。如果你需要回到,比方说,旧版本的匕首,只有你的模块和组件定义需要改变,而不是你的核心 类.
您的 类 不需要知道它们是如何生成的细节。明天您可能会根据范围使用不同的组件,或者您可能希望将您的组件从演示者中取出 类。你的核心 类 不应该因此改变。
它使您的模块测试更容易。无需 运行 代码生成或通过您的应用程序替换组件实例。只需在构造函数中直接注入模拟或测试模块即可。
只有在模块的生命周期不受您控制的情况下,才应使用字段和方法注入。 Android 环境中的活动或片段就是这种情况。在该用例之外,这些方法只是问题的根源。
如果你的依赖是通过组件/模块提供的,那么当依赖被创建时组件将一直存在。所以你可以在它的构造函数中调用字段注入。没有比这更简单的了。