为什么注入后我的字段为空?如何注入我的物体? [英] Why is my field `null` after injection? How do I inject my object?

查看:63
本文介绍了为什么注入后我的字段为空?如何注入我的物体?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个规范问题,因为对使用Dagger 2进行对象初始化存在很多误解.

This is a Canonical Question because there are a lot of misconceptions about object initialization with Dagger 2.

如果您的问题被标记为重复,请仔细阅读这篇文章,并确保了解构造函数注入和字段注入之间的区别.

If your question was flagged as a duplicate please read this post carefully and make sure to understand the difference between constructor injection and field injection.

我尝试将Context注入到演示者中,但是在尝试使用它时会收到NullPointerException.

I try to inject a Context into my presenter, but I get a NullPointerException when trying to use it.

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);
  }
}

我在这里的活动"中插入主持人:

I inject the presenter in my Activity here:

class MyActivity extends Activity {

  @Inject MyPresenter presenter;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    createMyActivityComponent().inject(this);
  }
}

推荐答案

以上内容同时包含构造函数和字段注入,但均未正确.如果我们从MyPresenter中删除了所有@Inject注释,则该示例的行为将相同,因为我们没有使用任何注释.

The above includes both constructor and field injection, but neither done right. The example would behave the same if we removed all the @Inject annotations from MyPresenter since we're not using any of them.

@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

确保使用 构造函数注入字段注入.混合两者通常会在您的设置或理解上表示错误.

Make sure to use either constructor injection or field injection. Mixing both will usually indicate an error in your setup or understanding.

    字段上的
  • @Inject字段注入
  • 的标记 构造函数上的
  • @Inject构造函数注入
  • 的标记
  • @Inject on a field is a marker for field injection
  • @Inject on a constructor is a marker for constructor injection

这意味着您的班级应该有

This means your class should have either of

    构造函数上的
  • 一个单个 @Inject,或者
  • 所有要初始化的字段上的@Inject ,但构造函数上没有
  • a single @Inject on the constructor, or
  • a @Inject on all the fields to initialize, but none on the constructor!

不要在任何地方撒上@Inject,不要指望一切正常!请确保将注释放置在需要的地方.不要混用字段和构造函数注入!

Don't sprinkle @Inject everywhere and expect things to work! Make sure to place the annotation where needed. Don't mix field and constructor injection!

构造函数注入优于字段注入,因为它创建了一个初始化且可用的对象.字段注入将与Framework创建对象的Framework组件一起使用.您必须手动调用component.inject(object)才能执行字段注入,否则尝试使用任何带注释的字段为空.

Constructor injection should be favored over field injection as it creates an initialized and usable object. Field injection is to be used with Framework components where the Framework creates the objects. You have to manually call component.inject(object) for field injection to be performed, or any annotated fields will be null when you try to use them.

顾名思义,您将依赖项作为参数 在构造函数中 .构造函数上的注释告诉Dagger有关对象的信息,然后它可以通过使用所有必需的依赖项对其进行调用来为您创建对象. Dagger在创建对象后还将注入任何带注释的字段或方法,但是通常应优先使用普通的构造方法注入,因为它不会隐藏任何依赖项.

As the name suggests you put your dependencies as parameters in the constructor. The annotation on the constructor tells Dagger about the object and it can then create the object for you by calling it with all the required dependencies. Dagger will also inject any annotated fields or methods after creating the object, but plain constructor injection should usually be favored as it doesn't hide any dependencies.

使用匕首创建对象还意味着无需在模块中使用@Provides方法创建对象.您需要做的就是将@Inject添加到构造函数中并声明依赖项.

Dagger creating the object also means there is no need for a @Provides method in your module that creates the object. All you need to do is add @Inject to the constructor and declare the dependencies.

class MyPresenter {

  private Context context;
  private MyView view;

  @Inject
  MyPresenter(MyView view, Context context) {
    this.view = view;
    this.context = context
  }
}

如果要将实现绑定到接口,仍然不需要自己创建对象.

If you want to bind your implementation to an interface, there is still no need to create the object yourself.

@Module class MyModule {

  @Provides
  MyPresenter providePresenter(MyPresenterImpl presenter) {
    // Dagger creates the object, we return it as a binding for the interface!
    return presenter;
  }
}

上述用例甚至还有一个更短(且性能更高)的版本:

And there is even a shorter (and more performant) version of the above use-case:

@Module interface MyModule {

  @Binds
  MyPresenter providePresenter(MyPresenterImpl presenter)
}

构造函数注入应该是使用Dagger的默认方式.确保您不要自己打电话给new ,否则您会误解了这个概念.

Constructor injection should be your default way of using Dagger. Make sure that you don't call new yourself or you misunderstood the concept.

有些时候,您不能使用构造函数注入,例如Android中的Activity是由Framework创建的,因此您不应覆盖构造函数.在这种情况下,我们可以使用场注入.

There are times when you can't use constructor injection, e.g. an Activity in Android gets created by the Framework and you shouldn't override the constructor. In this case we can use field injection.

要使用字段注入,您需要注释要用@Inject初始化的所有字段,并向应处理注入的组件添加void inject(MyActivity activity)方法.

To use field injection you annotate all the fields that you want initialized with @Inject and add a void inject(MyActivity activity) method to the component that should handle the injection.

@Component
interface MyComponent {
  void inject(MyActivity activity);
}

在代码中的某个地方,您必须调用component.inject(myActivity) ,否则这些字段将不会初始化.onCreate(..)

And somewhere in your code you have to call component.inject(myActivity) or the fields will not be initialized. e.g. in onCreate(..)

void onCreate(..) {
  // fields still null / uninitialized
  myComponent.inject(this);
  // fields are now injected!

  // ...
}

场注入不是可传递的.仅仅因为您注入了活动,并不意味着Dagger也将注入其注入的演示者的字段.您必须手动注入每个对象,这就是为什么您应该赞成构造函数注入的原因之一.

Field injection is not transitive. Just because you inject an Activity this does not mean that Dagger will also inject the fields of the presenter it injected. You have to inject every object manually, which is one reason why you should favor constructor injection.

有一些工具可以帮助减轻创建组件和注入对象的样板,例如AndroidInjection.inject(),这将为您做到这一点,但这仍然是必须要做的.另一个示例是AndroidInjection,后者随后将创建您的组件并注入该对象.

There are tools that help mitigate the boilerplate of creating components and injecting your objects like AndroidInjection.inject() which will do this for you, but it still has to be done. Another example is AppInjector which adds various lifecycle listeners to inject your Activities and Fragments, but it will still call AndroidInjection which then creates your component and injects the object.

请确保在使用对象之前先注入对象,并且没有构造函数带有@Inject注释,以避免混淆.

Make sure that you inject the object before using it and that there is no constructor annotated with @Inject to avoid confusion.

还有较少使用的方法注入,当然Dagger无法注入第三方库,而您拥有的在您的模块中构建和提供.

There is also the lesser used method injection and of course Dagger can't inject third party libraries, which you have to construct and provide in your modules.

这篇关于为什么注入后我的字段为空?如何注入我的物体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆