java Dagger 2:将用户输入的参数注入对象
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37516736/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Dagger 2: Injecting user inputted parameter into object
提问by Jay Sidri
Say I have a class Utilthat takes in a object - an instance of class Validator.
假设我有一个Util类,它接受一个对象 - 类Validator 的一个实例。
Since I want to avoid instantiating the Validator class within Util, I pass it in via a constructor:
因为我想避免在 Util 中实例化 Validator 类,所以我通过构造函数传入它:
public class Util {
@Inject
public Util(Validator validator) {
}
}
I have a module that provides the Validator instance:
我有一个提供 Validator 实例的模块:
@Provides
@Singleton
Validator provideValidator() {
return Validator.getInstance();
}
and an instance of the Util class:
和 Util 类的一个实例:
@Provides
Util provideUtil(Validator validator) {
return new Util(validator);
}
I have a component wired up that would give me an instance of Util:
我连接了一个组件,它会给我一个 Util 实例:
Util getUtil()
so within my activity, I could call it like:
所以在我的活动中,我可以这样称呼它:
Util myUtil = getComponent.getUtil();
All of that works fine - myUtil has a proper instance of Validator class when instantiated.
所有这些都可以正常工作 - myUtil 在实例化时有一个正确的 Validator 类实例。
Now I want to pass in a String variable named address(which is user input via a UI). I want to change the constructor so I pass in both an instance of Validator and the user inputted String:
现在我想传入一个名为address的字符串变量(这是用户通过 UI 输入的)。我想更改构造函数,因此我传入了 Validator 的实例和用户输入的字符串:
@Inject
public Util(Validator validator, String address) {
}
I just can't get my head around how to pass that 2nd parameter. Can someone tell me how?
我只是无法理解如何传递第二个参数。有人可以告诉我怎么做吗?
Ideally, I want to instantiate Util like:
理想情况下,我想像这样实例化 Util:
Util myUtil = getComponent.getUtil(txtAddress.getText());
回答by Semafoor
I had the same question as you when I started looking into Dagger 2 a couple of weeks ago. I found information on this (and most other Dagger 2-related issues) difficult to come by, so I hope this helps!
几周前我开始研究 Dagger 2 时,我和你有同样的问题。我发现很难获得关于此(以及大多数其他 Dagger 2 相关问题)的信息,所以我希望这会有所帮助!
The most basic answer is that you cannot. What you are looking for is something that is called assisted injection, and it is not part of Dagger 2. Some other dependency injection (DI) frameworks, such as Guice, do offer this feature, so you might look into those. Of course, there are still ways to do what you want to do using Dagger 2.
最基本的答案是你不能。您正在寻找的是称为辅助注入 的东西,它不是 Dagger 2 的一部分。其他一些依赖注入 (DI) 框架,例如Guice,确实提供了此功能,因此您可能会研究这些。当然,仍然有一些方法可以使用 Dagger 2 完成您想做的事情。
Factories factories factories
工厂工厂工厂
The standard way to do what you want to do in combination with DI is by using the Factory pattern. Basically, you create an injectable factory class that takes runtime parameters such as address
as arguments to the object creation methods that it provides.
结合 DI 做您想做的事情的标准方法是使用工厂模式。基本上,您创建一个可注入的工厂类,它接受运行时参数,例如address
它提供的对象创建方法的参数。
In your case, you would need a UtilFactory
into which Dagger 2 injects a Validator
upon instantation and which offers a method create(String address)
that creates instances of Util
. UtilFactory
should keep a reference to the injected instance of Validator
so that it has everything it needs to create an instance of Util
in the create
method.
在您的情况下,您将需要UtilFactory
Dagger 2Validator
在create(String address)
实例化时注入,并提供创建Util
. UtilFactory
应该保留对注入的实例的引用,Validator
以便它拥有Util
在create
方法中创建实例所需的一切。
Wring code for many such factories can be cumbersome. You should definitely take a look at AutoFactory, which eases some of the burden. Guice's assisted injection seems to work quite similar to Dagger 2 + AutoFactory (albeit with even nicer syntactic sugar).
为许多此类工厂编写代码可能很麻烦。您绝对应该看看AutoFactory,它减轻了一些负担。Guice 的辅助注入似乎与 Dagger 2 + AutoFactory 非常相似(尽管语法糖更好)。
More modules / components
更多模块/组件
I doubt this is something that you would like to do in this case, but you couldjust create a module that provides the address (and instantiate a new component). You do not have to create a new @Module class for every possible address. Instead, you can just pass the address as an argument to the constructor of the module. You could use the @BindsInstance-annotation as suggested by teano to achieve a similar result.
我怀疑这是您在这种情况下想要做的事情,但您可以创建一个提供地址的模块(并实例化一个新组件)。您不必为每个可能的地址创建一个新的 @Module 类。相反,您可以将地址作为参数传递给模块的构造函数。您可以按照teano的建议使用@BindsInstance-annotation来实现类似的结果。
I am not sure if this is an anti-pattern or not. To me, this seems like an acceptable route in some cases, but only when you are actually using the same e.g. address for the initialisation of "many" objects. You definitely do not want to instantiate a new component anda new model for each object that requires injection. It is not efficient, and if you are not careful you will end up with more boilerplate code than without Dagger.
我不确定这是否是一种反模式。对我来说,这在某些情况下似乎是可以接受的路线,但只有当您实际使用相同的地址来初始化“许多”对象时。您绝对不想为每个需要注入的对象实例化一个新组件和一个新模型。它效率不高,如果您不小心,最终会得到比没有 Dagger 时更多的样板代码。
Do not (always) use DI: Injectables versus newables
不要(总是)使用 DI:可注射物与可再生物
Something that was immensely useful to me when learning about DI frameworks was the realisation that using a DI framework does notmean that you have to DI to initialise allof your objects. As a rule of thumb: inject objects that you know of at compile time and that have static relations to other objects; do not inject runtime information.
一些了解DI框架时,这是对我来说非常有用是实现了使用DI框架并不能意味着你必须DI初始化所有的对象。作为一个经验法则:注入你在编译时知道的并且与其他对象有静态关系的对象;不要注入运行时信息。
I think thisis a good post on the subject. It introduces the concept of 'newables' and 'injectables'.
我认为这是一篇关于这个主题的好帖子。它引入了“可再生能源”和“可注射药品”的概念。
- Injectablesare the classes near the root of your DI graph. Instances of these classes are the kind of objects that you expect your DI framework to provide and inject. Manager- or service-type objects are typical examples of injectables.
- Newablesare objects at the fringes of your DI graph, or that are not even really part of your DI graph at all.
Integer
,Address
etc. are examples of newables.
- Injectables是靠近 DI 图根的类。这些类的实例是您希望 DI 框架提供和注入的对象类型。管理器或服务类型对象是可注入的典型示例。
- Newables是位于 DI 图边缘的对象,或者根本不是 DI 图的一部分。
Integer
,Address
等是newables的例子。
Broadly speaking, newables are passive objects, and there is no point in injecting or mocking them. They typically contain the "data" that is in your application and that is only available at runtime (e.g. your address). Newables should not keep references to injectables or vice versa (something the author of the post refers to as "injectable/newable-separation").
从广义上讲,newables 是被动对象,注入或模拟它们没有意义。它们通常包含在您的应用程序中并且仅在运行时可用的“数据”(例如您的地址)。Newables 不应该保留对可注射物的引用,反之亦然(这篇文章的作者将其称为“可注射/可再生分离”)。
In reality, I have found that it is not always easy or possible to make a clear distinction between injectables and newables. Still, I think that they are nice concepts to use as part of your thinking process. Definitely think twice before adding yet another factory to your project!
实际上,我发现在可注射物和可再生物之间做出明确区分并不总是容易或不可能的。不过,我认为它们是很好的概念,可以用作您思考过程的一部分。在为您的项目添加另一个工厂之前一定要三思!
In your case, I think it would make sense to treat Util
as an injectable and the address as a newable. This means that the address should not be part of the Util
class. If you want to use instance of Util
for e.g. validating/... addresses, just pass the address that you want to validate as an argument to the validation/... method.
在您的情况下,我认为将Util
地址视为可注入对象并将地址视为可更新对象是有意义的。这意味着地址不应该是Util
类的一部分。如果您想使用Util
例如验证/...地址的实例,只需将您要验证的地址作为参数传递给验证/...方法。
回答by teano
You can change the component builder to inject instances. See: https://google.github.io/dagger/users-guide#binding-instances
您可以更改组件构建器以注入实例。请参阅:https: //google.github.io/dagger/users-guide#binding-instances
In your case, you can call:
在您的情况下,您可以致电:
Util myUtil = DaggerMyComponent.builder().withAddress(txtAddress.getText()).build().getComponent().getUtil();
if MyComponent is defined as:
如果 MyComponent 定义为:
@Component(modules = UtilModule.class)
interface MyComponent{
MyComponent getComponent();
@Component.Builder
interface Builder {
@BindsInstance Builder withAddress(@Address String address); //bind address instance
MyComponent build();
}
}
And UtilModule:
和 UtilModule:
@Module
class UtilModule{
@Provides
Util getUtil(Validator validator, @Address String address){ //inject address instance
return new Util(validator, address);
}
}
Validator must be provided with an @Inject annotated constructor or a @Provides annotated method in a module class passed to MyComponent's modules in the @Component annotation.
Validator 必须在传递给@Component 注释中的MyComponent 模块的模块类中提供带有@Inject 注释的构造函数或@Provides 注释的方法。
回答by Francis Shi
when initiate Module, you can pass some parameters like this:
当启动Module时,你可以传递一些这样的参数:
public NetServiceModule(String baseUrl, boolean isLogEnabled, CookieJar cookieJar) {
this.mBaseUrl = baseUrl;
this.mIsLogEnabled = isLogEnabled;
this.mCookieJar = cookieJar;
}
And then get the component in "Container Class":
然后在“Container Class”中获取组件:
NetServiceComponent component = DaggerNetServiceComponent.builder()
.netServiceModule(new NetServiceModule(baseUrl, mIsLogEnabled, cookieJar))
.build();
component.inject(this);
With Providesmethod to provide Injectionwhich generate by some parameters if it need:
使用提供方法来提供注入,如果需要,注入由一些参数生成:
@Provides
Retrofit provideRetrofit(OkHttpClient httpClient, GsonConverterFactory gsonConverterFactory, NetCallAdapterFactory netCallAdapterFactory) {
return new Retrofit.Builder()
.client(httpClient)
.baseUrl(mBaseUrl)
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(netCallAdapterFactory)
.build();
}
回答by Koushik Deb
@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 ");
}
}
}