Dagger 2:将用户输入的参数注入对象

时间:2016-05-30 02:04:35

标签: java android dagger-2

假设我有一个类 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());

4 个答案:

答案 0 :(得分:82)

几周前,当我开始研究Dagger 2时,我遇到了同样的问题。我发现有关此信息(以及大多数其他Dagger 2相关问题)的信息很难找到,所以我希望这会有所帮助!

最基本的答案是你做不到。您正在寻找的是被称为辅助注入的东西,它不是Dagger 2的一部分。其他一些依赖注入(DI)框架,例如Guice,确实提供了此功能,所以你可能会研究那些。当然,仍然有办法使用Dagger 2做你想做的事。

工厂工厂

与DI结合使用的标准方法是使用Factory模式。基本上,您创建一个可注入的工厂类,它将运行时参数(如address)作为它提供的对象创建方法的参数。

在您的情况下,您需要一个UtilFactory Dagger 2在即时时注入Validator,并提供创建create(String address)实例的方法UtilUtilFactory应该保留对Validator的注入实例的引用,以便它具有在Util方法中创建create实例所需的一切。

许多此类工厂的拧密码可能很麻烦。你一定要看看AutoFactory,这可以减轻一些负担。 Guice的辅助注射似乎与Dagger 2 + AutoFactory非常相似(虽然具有更好的语法糖)。

更多模块/组件

我怀疑在这种情况下你想要这样做,但你可以只创建一个提供地址的模块(并实例化一个新组件)。您不必为每个可能的地址创建新的@Module类。相反,您可以将地址作为参数传递给模块的构造函数。您可以使用teano建议的@BindsInstance-annotation来获得类似的结果。

我不确定这是否是反模式。对我来说,在某些情况下,这似乎是一种可接受的路线,但只有当您实际使用相同的路线时,例如初始化"许多"的地址对象。您绝对不希望为每个需要注入的对象实例化一个新组件一个新模型。效率不高,如果你不小心,你会得到比没有Dagger更多的样板代码。

不要(总是)使用DI:注射剂与新品

在学习DI框架时,对我来说非常有用的东西是使用DI框架确实意味着您必须使用DI来初始化所有对象。根据经验:在编译时注入你知道的并且与其他对象有静态关系的对象;不要注入运行时信息。

我认为this是关于这个主题的好帖子。它介绍了' newables'和'注射剂'。

  • Injectables 是DI图根目录附近的类。这些类的实例是您希望DI框架提供和注入的对象类型。管理者或服务类型对象是注射剂的典型示例。
  • Newables 是DI图边缘的对象,或者甚至根本不是DI图的一部分。 IntegerAddress等是新手的例子。

从广义上讲,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 ");


}

}