Dagger 2.10 Subcomponentes y constructores de Android

Usando las nuevas (en 2.10) clases dagger.android, bash inyectar cosas usando un Subcomponente que depende de otros Módulos, y, por lo tanto, tengo un Constructor con adaptadores para esos módulos. La documentación en https://google.github.io/dagger/android.html describe esto, pero no está claro cómo escribir y / o invocar esos setters.

Citando del enlace de arriba:

AndroidInjection.inject () obtiene un DispatchingAndroidInjector de la Aplicación y pasa tu actividad a Inject (Activity). El DispatchingAndroidInjector busca AndroidInjector.Factory para la clase de su actividad (que es YourActivitySubcomponent.Builder), crea el AndroidInjector (que es YourActivitySubcomponent) y pasa su actividad a Inject (YourActivity).

Me parece que para poder llamar a los incubadores para el Constructor, ¿tengo que llegar allí y asegurarme de que el Constructor tiene todos los datos necesarios? El problema que estoy viendo es que, en tiempo de ejecución, obtengo una IllegalStateException: MODULE must be set , cuando el generador generado para mi Subcomponente es invocado por AndroidInjector.

El Subcomponente en cuestión es, de hecho, para un Fragmento, no una Actividad, pero no estoy seguro de que eso importe. ¿Alguna idea sobre cómo hacer esto?

En resumen, se supone que debes anular la llamada a seedInstance on the Builder (que es una clase abstracta en lugar de una interfaz) para proporcionar otros módulos que necesites.

editar : antes de hacerlo, verifique y asegúrese de que realmente necesita pasar ese Módulo. Como Damon agregó en una respuesta separada , si estás creando un Módulo específico para tu clase de Android, puedes confiar en la inyección automática de esa clase para extraer la configuración o instancia del gráfico en ese punto. Favorezca su enfoque si es más fácil simplemente eliminar los parámetros del constructor de su Módulo, que también puede proporcionar un mejor rendimiento, ya que evitan instancias innecesarias y llamadas a métodos virtuales.


Primero, dagger.android en 30 segundos: en lugar de tener cada Actividad o Fragmento sobre su padre, la Actividad (o Fragmento) llama a AndroidInjection.inject(this) , que verifica la Aplicación de HasActivityInjector (o fragmentos principales, actividad y aplicación) para HasFragmentInjector ). La idea es que usted contribuya con un enlace a un Map creado por Map , donde los enlaces contribuidos son casi siempre constructores de subcomponentes que se escriben y que construyen subcomponentes específicos de un objeto.

Como podría decir de AndroidInjection.inject(this) y AndroidInjector.Factory.create(T instance) , no tiene muchas oportunidades de pasar detalles específicos de la actividad o del fragmento a su Builder. En cambio, la idea es que su constructor de subcomponentes anule la implementación de seedInstance . Como en los documentos para seedInstance :

Proporciona una instance para usar en el gráfico vinculante del AndroidInjector incorporado. Por defecto, esto se usa como un método BindsInstance , pero puede ser reemplazado para proporcionar cualquier módulo que necesite una referencia a la actividad.

Esta debería ser la misma instancia que se pasará a inject(Object) .

Eso se vería así:

 @Subcomponent(modules = {OneModule.class, TwoModule.class}) public interface YourActivitySubcomponent extends AndroidInjector { // inject(YourActivity) is inherited from AndroidInjector @Builder public abstract class Builder extends AndroidInjector.Builder { // 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())); } } } 

La suposición aquí es que debe esperar la instancia de activity para los módulos. Si no es así, también tiene la opción de llamarlos cuando vincula el subcomponente:

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

… pero si puedes hacer eso, entonces podrías más fácilmente ocuparte de esas ataduras anulando esos módulos, implementando un constructor zero-arg que pueda suministrar los parámetros del constructor del Módulo, y permitiendo que Dagger cree eso como lo hace para cualquier Módulos con constructores públicos de cero arg.

eso funciona, pero es innecesario. El método seedInstance proporciona la instancia de actividad en el gráfico, por lo que puede tener MyActivityModule sin estado y solo solicitar MyActivity en sus métodos @Provides.

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

Hacer esto guarda la instancia del módulo y permite que las fábricas generadas sean más ágiles.

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