android dagger-2

android - ¿Por qué mi campo es "nulo" después de la inyección? ¿Cómo inyecto mi objeto?



dagger-2 (2)

Esta es una pregunta canónica porque hay muchas ideas falsas sobre la inicialización de objetos con Dagger 2.

Si su pregunta se marcó como un duplicado , lea esta publicación detenidamente y asegúrese de comprender la diferencia entre la inyección de constructor y la inyección de campo.

Intento inyectar un Context en mi presentador, pero obtengo una NullPointerException cuando intento usarlo.

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

Mi módulo se ve así

@Module class MyModule { @Provides MyPresenter provideMyPresenter(MyView view) { return new MyPresenter(view); } }

Inyecto el presentador en mi actividad aquí:

class MyActivity extends Activity { @Inject MyPresenter presenter; @Override public void onCreate(Bundle savedInstanceState) { createMyActivityComponent().inject(this); } }


Elimine @Inject del contexto y cree un módulo separado para proporcionar dependencia de contexto

@Module public class ContextModule { private final Context context; public ContextModule(Context context) { this.context = context; } @Provides @MyAppScope public Context getContext() { return context; } }

luego crea tu DaggerComponent. (Lo he creado en la clase de aplicación y esto se refiere a ApplicationContext

component = DaggerDaggerAppComponent.builder() .contextModule(new ContextModule(this)) .MyModule() .build();

Puede omitir .MyModule () si lo desea porque, a diferencia del módulo Context, no tiene dependencia externa.


Lo anterior incluye tanto el constructor como la inyección de campo , pero ninguno de los dos está bien hecho . El ejemplo se comportaría de la misma manera si eliminamos todas las anotaciones de MyPresenter de MyPresenter ya que no estamos usando ninguna de ellas.

@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

Asegúrese de usar la inyección de constructor o la inyección de campo. Mezclar ambos generalmente indicará un error en su configuración o comprensión.

  • @Inject en un campo es un marcador para la inyección de campo
  • @Inject en un constructor es un marcador para la inyección del constructor

Esto significa que su clase debe tener cualquiera de

  • un solo @Inject en el constructor, o
  • ¡ @Inject en todos los campos para inicializar , pero ninguno en el constructor !

¡No rocíe @Inject todas partes y espere que las cosas funcionen! Asegúrese de colocar la anotación donde sea necesario. ¡No mezcle la inyección de campo y de constructor!

La inyección de constructor debe ser favorecida sobre la inyección de campo ya que crea un objeto inicializado y utilizable. La inyección de campo se debe utilizar con componentes de Framework donde Framework crea los objetos. Debe llamar manualmente a component.inject(object) para que se realice la inyección de campo, o cualquier campo anotado será nulo cuando intente usarlos.

Inyección de constructor

Como su nombre indica, coloca tus dependencias como parámetros en el constructor . La anotación en el constructor le dice a Dagger sobre el objeto y luego puede crear el objeto para usted llamándolo con todas las dependencias requeridas. Dagger también inyectará los campos o métodos anotados después de crear el objeto, pero la inyección de constructor simple generalmente debe ser favorecida ya que no oculta ninguna dependencia.

Dagger al crear el objeto también significa que no hay necesidad de un método @Provides en su módulo que cree el objeto. Todo lo que necesita hacer es agregar @Inject al constructor y declarar las dependencias.

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

Si desea vincular su implementación a una interfaz, aún no es necesario crear el objeto usted mismo.

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

E incluso hay una versión más corta (y más eficaz) del caso de uso anterior:

@Module interface MyModule { @Binds MyPresenter providePresenter(MyPresenterImpl presenter) }

La inyección de constructor debería ser la forma predeterminada de usar Dagger. Asegúrate de no llamar new ti mismo o no has entendido el concepto.

Inyección de campo

Hay momentos en los que no puede usar la inyección del constructor, por ejemplo, el Framework crea una Actividad en Android y no debe anular el constructor. En este caso podemos usar la inyección de campo .

Para usar la inyección de campo, anote todos los campos que desea inicializar con @Inject y agregue un método de void inject(MyActivity activity) al componente que debe manejar la inyección.

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

Y en algún lugar de su código debe llamar a component.inject(myActivity) o los campos no se inicializarán. por ejemplo en onCreate(..)

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

La inyección de campo no es transitiva . El hecho de que inyecte una actividad no significa que Dagger también inyecte los campos del presentador que inyectó. Debe inyectar cada objeto manualmente, lo cual es una razón por la que debería favorecer la inyección del constructor.

Existen herramientas que ayudan a mitigar la rutina de crear componentes e inyectar sus objetos como AndroidInjection.inject() que lo hará por usted, pero aún debe hacerse. Otro ejemplo es AppInjector que agrega varios oyentes del ciclo de vida para inyectar sus Actividades y Fragmentos, pero aún llamará a AndroidInjection que luego crea su componente e inyecta el objeto.

Asegúrese de inyectar el objeto antes de usarlo y de que no haya ningún constructor anotado con @Inject para evitar confusiones.

¿Qué más?

También existe el método de inyección menos utilizado y, por supuesto, Dagger no puede inyectar bibliotecas de terceros, que debe construir y proporcionar en sus módulos.