这是Canonical Question,因为Dagger 2对对象初始化存在很多误解。
如果您的问题被标记为重复,请仔细阅读此文章,并确保了解构造函数注入和字段注入之间的区别。
我尝试向我的演示者注入Context
,但在尝试使用它时会出现NullPointerException。
class MyPresenter {
@Inject Context context;
private MyView view;
@Inject
MyPresenter(MyView view) {
this.view = view;
}
}
我的模块看起来像这样
@Module
class MyModule {
@Provides
MyPresenter provideMyPresenter(MyView view) {
return new MyPresenter(view);
}
}
我在此活动中注入了演示者:
class MyActivity extends Activity {
@Inject MyPresenter presenter;
@Override
public void onCreate(Bundle savedInstanceState) {
createMyActivityComponent().inject(this);
}
}
答案 0 :(得分:5)
以上内容包括构造函数和字段注入,但既未正确。如果我们从@Inject
删除了所有MyPresenter
注释,则该示例的行为会相同,因为我们并未使用其中的任何注释。
@Provides
MyPresenter provideMyPresenter(MyView view) {
// no constructor injection, we create the object ourselves!
return new MyPresenter(view);
}
// also no mention anywhere of component.inject(presenter)
// so the fields won't be injected either
确保使用 构造函数注入或字段注入。混合两者通常表示您的设置或理解中存在错误。
@Inject
是字段注入 @Inject
是构造函数注入的标记 这意味着您的班级应该
@Inject
,或 不要在任何地方洒@Inject
并希望事情有效!确保将注释放在需要的地方。不要混合场和构造函数注入!
构造函数注入应该优于字段注入,因为它创建了一个初始化和可用的对象。字段注入将与框架组件一起使用,其中框架创建对象。当您尝试使用它们时,您必须手动调用@Inject
进行字段注入,或者任何带注释的字段将为空。
顾名思义,您将依赖项作为参数 置于构造函数 中。构造函数上的注释告诉Dagger关于该对象,然后它可以通过使用所有必需的依赖项调用它来为您创建对象。 Dagger也会在创建对象后注入任何带注释的字段或方法,但普通构造函数注入通常应该受到青睐,因为它不会隐藏任何依赖项。
创建对象的Dagger也意味着不需要模块中的component.inject(object)
方法来创建对象。您需要做的就是将@Provides
添加到构造函数并声明依赖项。
@Inject
如果要将实现绑定到接口,则仍然无需自己创建对象。
class MyPresenter {
private Context context;
private MyView view;
@Inject
MyPresenter(MyView view, Context context) {
this.view = view;
this.context = context
}
}
甚至还有一个更短(更高性能)的上述用例版本:
@Module class MyModule {
@Provides
MyPresenter providePresenter(MyPresenterImpl presenter) {
// Dagger creates the object, we return it as a binding for the interface!
return presenter;
}
}
构造函数注入应该是使用Dagger的默认方式。确保您不要自己致电@Module interface MyModule {
@Binds
MyPresenter providePresenter(MyPresenterImpl presenter)
}
或者您误解了这个概念。
有些时候无法使用构造函数注入,例如Android中的Activity由Framework创建,您不应该覆盖构造函数。在这种情况下,我们可以使用字段注入。
要使用字段注入,请注释要使用new
初始化的所有字段,并向应处理注入的组件添加@Inject
方法。
void inject(MyActivity activity)
在代码的某处,您必须致电@Component
interface MyComponent {
void inject(MyActivity activity);
}
,否则字段将不会被初始化。例如在component.inject(myActivity)
onCreate(..)
字段注入不可传递。仅仅因为你注入了一个Activity,这并不意味着Dagger也会注入它注入的主持人的字段。您必须手动注入每个对象,这是您应该支持构造函数注入的一个原因。
有些工具可以帮助减轻创建组件和注入像void onCreate(..) {
// fields still null / uninitialized
myComponent.inject(this);
// fields are now injected!
// ...
}
之类的对象的样板,这些对象将为您完成此任务,但仍需要完成。另一个例子是AppInjector
,它添加了各种生命周期监听器来注入你的活动和片段,但它仍会调用AndroidInjection.inject()
然后创建你的组件并注入对象。
确保在使用之前注入对象,并且没有使用AndroidInjection
注释的构造函数以避免混淆。
还有较少使用的method injection,当然Dagger无法注入第三方库,您必须在模块中构建和提供这些库。
答案 1 :(得分:0)
从上下文中删除 @Inject ,并创建一个单独的模块,以提供上下文依赖
@Module
public class ContextModule {
private final Context context;
public ContextModule(Context context) {
this.context = context;
}
@Provides
@MyAppScope
public Context getContext() {
return context;
}
}
然后创建你的DaggerComponent。 (我在Application类中创建了它,这个引用了 ApplicationContext
component = DaggerDaggerAppComponent.builder()
.contextModule(new ContextModule(this))
.MyModule()
.build();
如果需要,可以跳过 .MyModule(),因为与上下文模块不同,它没有外部依赖。