2017-04-12 187 views
12

使用新的(在2.10中)dagger.android类,我试图使用依赖于其他模块的子组件注入事物,因此,有一个具有这些模块的setter的Builder。有关https://google.github.io/dagger/android.html的文档描述了这一点,但不清楚如何实际编写和/或调用这些设置器。Dagger 2.10 Android子组件和构建器

从上面的链接引用:

AndroidInjection.inject() gets a DispatchingAndroidInjector from the Application and passes your activity to inject(Activity). The DispatchingAndroidInjector looks up the AndroidInjector.Factory for your activity’s class (which is YourActivitySubcomponent.Builder), creates the AndroidInjector (which is YourActivitySubcomponent), and passes your activity to inject(YourActivity).

在我看来,为了能够调用的setter方法生成器,我需要在那里得到的地方,并确保生成器拥有所有必要的数据?我看到的问题是,在运行时,我得到一个IllegalStateException: MODULE must be set,当我的子组件生成的构建器由AndroidInjector调用。

问题的子组件实际上是一个片段,而不是一个活动,但我不知道这应该重要。有关如何做到这一点的任何想法?

+1

参见[这](https://android.jlelse.eu/android-and-dagger-2-10-androidinjector-5e9c523679a3),最有可能会解决你的问题。 – azizbekian

+1

你可以发布一些简化的代码吗?你无法设置哪个模块? –

回答

25

总之,你应该override the call to seedInstance在Builder(这是一个抽象类,而不是一个接口),提供您所需要的其他模块。

编辑:在此之前,检查并确保您确实需要通过该模块。由于Damon added in a separate answer,如果您为Android类创建了特定的模块,您可以依靠该类的自动注入来将配置或实例从该图上拉出。如果仅仅从模块中消除构造函数参数更容易,也可以提供更好的性能,因为它们避免了不必要的实例和虚方法调用。


首先,dagger.android在30秒:而不是具有各活动或片段知道它的父,活动(或片段)调用AndroidInjection.inject(this),其检查HasActivityInjector(或父片段的应用,活动和申请HasFragmentInjector)。这个想法是,你贡献了一个绑定到一个multibindings创建Map<Class, AndroidInjector.Factory>,其中贡献绑定几乎你写的构建特定对象的子始终子建设者。

正如你可能从AndroidInjection.inject(this)AndroidInjector.Factory.create(T instance)告诉,你没有得到很多的机会,通过特定活动或特定片段,向您详细介绍构建的。取而代之的是,这个想法是,你的子组件构建覆盖seedInstance实施。如在文档的seedInstance

Provides instance to be used in the binding graph of the built AndroidInjector . By default, this is used as a BindsInstance method, but it may be overridden to provide any modules which need a reference to the activity.

This should be the same instance that will be passed to inject(Object) .

那会是这个样子:

@Subcomponent(modules = {OneModule.class, TwoModule.class}) 
public interface YourActivitySubcomponent extends AndroidInjector<YourActivity> { 

    // inject(YourActivity) is inherited from AndroidInjector<YourActivity> 

    @Builder 
    public abstract class Builder extends AndroidInjector.Builder<YourActivity> { 
    // Here are your required module builders: 
    abstract Builder oneModule(OneModule module); 
    abstract Builder twoModule(TwoModule module); 

    // By overriding seedInstance, you don't let Dagger provide its 
    // normal @BindsInstance implementation, but you can supply the 
    // instance to modules or call your own BindsInstance: 
    @Override public void seedInstance(YourActivity activity) { 
     oneModule(new OneModule(activity)); 
     twoModule(new TwoModule(activity.getTwoModuleParameter())); 
    } 
    } 
} 

这里的假设是,你需要等待activity实例模块。如果没有,那么你也有调用这些的选项,当您绑定子:

@Provides @IntoMap @ActivityKey(YourActivity.class) 
AndroidInjector.Factory bindInjector(YourActivitySubcomponent.Builder builder) { 
    return builder 
     .oneModule(new OneModule(...)) 
     .twoModule(new TwoModule(...)); 
} 

...但如果你能做到这一点,那么你可以更轻松地通过重写这些模块照顾那些绑定,实现可供给模块的构造函数参数零参数的构造函数,并让匕首创造者,因为它确实为公共零参数构造的任何模块。

+0

完美,谢谢! –

+2

这完全工作!这在文档中没有提及,但是这使得使用匕首2 +的新用户难以理解文档。 – ArunL

+0

不知道为什么我的实现返回一个错误为“错误:(154,5)错误:方法没有覆盖或实现超类型的方法” –

2

确实有效,但没有必要。 seedInstance方法将活动实例提供到图中,因此您可以让MyActivityModule没有状态,只需在@Provides方法中请求MyActivity。

class MyActivityModule { 
    @Provides 
    static SomethingDerivedFromMyActivity providesMethod(MyActivity myActivity) { 
    return myActivity.somethingDerived(); 
    } 
} 

这样做节省了模块实例,并允许生成的工厂要精简。

https://github.com/google/dagger/issues/615

+0

+1:你(和我的同事Ron)是对的,当然,假设你的设置足够重新编辑模块以包含对你的Activity的引用。如果你的模块来自第三方,或者设计用于更多活动而不仅仅是MyActivity,那么你可能不得不使用我更复杂的设置(本身也在文档中建议)。假设提问者需要带有构造函数的有状态模块,我回答了这个问题,因为他们提到需要Builder,但是如果你不这样做,那么当然事情可以更容易地表示。 –

+0

同意但我的问题是,当使用您的解决方案时,编译器大声抗议“错误:(154,5)错误:方法不会覆盖或实现超类型的方法”。我完全按照步骤,在检查生成的代码后,我发现错误是在'oneModule()'抽象方法的实现中给出的。不知道为什么会发生,我正在使用匕首2.10。无论如何,让我做一些更多的测试,也许我可以在代码中找到错误的地方。 –

+0

你能告诉我吗?这听起来像'oneModule'不是公开的或抽象的,或者这个类不是,或者其他。 –

相关问题