假设我有一个类 Util ,它接受一个对象 - 类 Validator 的实例。
因为我想避免在Util中实例化Validator类,所以我通过构造函数传递它:
public class Util {
@Inject
public Util(Validator validator) {
}
}
我有一个提供Validator实例的模块:
@Provides
@Singleton
Validator provideValidator() {
return Validator.getInstance();
}
和Util类的一个实例:
@Provides
Util provideUtil(Validator validator) {
return new Util(validator);
}
我有一个连接的组件会给我一个Util的实例:
Util getUtil()
所以在我的活动中,我可以称之为:
Util myUtil = getComponent.getUtil();
所有这些都可以正常工作 - myUtil在实例化时有一个适当的Validator类实例。
现在我想传入一个名为地址的字符串变量(通过UI输入用户)。我想更改构造函数,所以我传入Validator的实例和用户输入的String:
@Inject
public Util(Validator validator, String address) {
}
我无法理解如何传递第二个参数。谁能告诉我怎么样?
理想情况下,我想实例化Util,如:
Util myUtil = getComponent.getUtil(txtAddress.getText());
答案 0 :(得分:82)
几周前,当我开始研究Dagger 2时,我遇到了同样的问题。我发现有关此信息(以及大多数其他Dagger 2相关问题)的信息很难找到,所以我希望这会有所帮助!
最基本的答案是你做不到。您正在寻找的是被称为辅助注入的东西,它不是Dagger 2的一部分。其他一些依赖注入(DI)框架,例如Guice,确实提供了此功能,所以你可能会研究那些。当然,仍然有办法使用Dagger 2做你想做的事。
与DI结合使用的标准方法是使用Factory模式。基本上,您创建一个可注入的工厂类,它将运行时参数(如address
)作为它提供的对象创建方法的参数。
在您的情况下,您需要一个UtilFactory
Dagger 2在即时时注入Validator
,并提供创建create(String address)
实例的方法Util
。 UtilFactory
应该保留对Validator
的注入实例的引用,以便它具有在Util
方法中创建create
实例所需的一切。
许多此类工厂的拧密码可能很麻烦。你一定要看看AutoFactory,这可以减轻一些负担。 Guice的辅助注射似乎与Dagger 2 + AutoFactory非常相似(虽然具有更好的语法糖)。
我怀疑在这种情况下你想要这样做,但你可以只创建一个提供地址的模块(并实例化一个新组件)。您不必为每个可能的地址创建新的@Module类。相反,您可以将地址作为参数传递给模块的构造函数。您可以使用teano建议的@BindsInstance-annotation来获得类似的结果。
我不确定这是否是反模式。对我来说,在某些情况下,这似乎是一种可接受的路线,但只有当您实际使用相同的路线时,例如初始化"许多"的地址对象。您绝对不希望为每个需要注入的对象实例化一个新组件和一个新模型。效率不高,如果你不小心,你会得到比没有Dagger更多的样板代码。
在学习DI框架时,对我来说非常有用的东西是使用DI框架确实不意味着您必须使用DI来初始化所有对象。根据经验:在编译时注入你知道的并且与其他对象有静态关系的对象;不要注入运行时信息。
我认为this是关于这个主题的好帖子。它介绍了' newables'和'注射剂'。
Integer
,Address
等是新手的例子。从广义上讲,newables是被动对象,注入或嘲弄它们是没有意义的。它们通常包含"数据"在您的应用程序中,并且仅在运行时可用(例如您的地址)。 Newables不应该保留对注射剂的引用,反之亦然(该帖子的作者称之为"注射/新的分离")。
实际上,我发现在注射剂和新药之间做出明确区分并不总是容易或可能的。尽管如此,我认为它们是很好的概念,可以用作思考过程的一部分。在将另一家工厂添加到您的项目之前,一定要三思而后行!
在您的情况下,我认为将Util
视为注射剂并将地址视为新品是有意义的。这意味着该地址不应该是Util
类的一部分。如果您想使用Util
的实例,例如验证/ ...地址,只需将您要验证的地址作为参数传递给validation / ...方法。
答案 1 :(得分:6)
您可以将组件构建器更改为注入实例。请参阅:https://google.github.io/dagger/users-guide#binding-instances
在您的情况下,您可以致电:
@Component(modules = UtilModule.class)
interface MyComponent{
MyComponent getComponent();
@Component.Builder
interface Builder {
@BindsInstance Builder withAddress(@Address String address); //bind address instance
MyComponent build();
}
}
如果MyComponent定义为:
@Module
class UtilModule{
@Provides
Util getUtil(Validator validator, @Address String address){ //inject address instance
return new Util(validator, address);
}
}
和UtilModule:
pip install scikit-image
Validator必须在@Component批注中传递给MyComponent模块的模块类中提供@Inject带注释的构造函数或@Provides带注释的方法。
答案 2 :(得分:2)
启动Module时,您可以传递一些参数:
public NetServiceModule(String baseUrl, boolean isLogEnabled, CookieJar cookieJar) {
this.mBaseUrl = baseUrl;
this.mIsLogEnabled = isLogEnabled;
this.mCookieJar = cookieJar;
}
然后将组件放入" Container Class":
NetServiceComponent component = DaggerNetServiceComponent.builder()
.netServiceModule(new NetServiceModule(baseUrl, mIsLogEnabled, cookieJar))
.build();
component.inject(this);
使用提供方法提供注入,如果需要,可以通过某些参数生成:
@Provides
Retrofit provideRetrofit(OkHttpClient httpClient, GsonConverterFactory gsonConverterFactory, NetCallAdapterFactory netCallAdapterFactory) {
return new Retrofit.Builder()
.client(httpClient)
.baseUrl(mBaseUrl)
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(netCallAdapterFactory)
.build();
}
答案 3 :(得分:0)
@Inject
Usermodel uuser;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
userComponent dc = DaggeruserComponent.create();
dc.injectMain(this);
historymodel hm = uuser.getHistorymodel();// get the models to pass user inputs
videoModel vm = uuser.getVideoModel();// get the models to pass user inputs
hm.setUid("userid ");
}
}