tutorial español dagger2 java dagger-2 lifecycle

java - dagger2 - dagger 2 tutorial español



¿Qué determina el ciclo de vida de un componente(gráfico de objeto) en Dagger 2? (1)

Estoy tratando de comprender los ámbitos en Dagger 2, específicamente el ciclo de vida de los gráficos de ámbito. ¿Cómo se crea un componente que se limpiará cuando abandone el ámbito?

En el caso de una aplicación de Android, al usar Dagger 1.x generalmente tiene un alcance raíz en el nivel de la aplicación que ampliaría para crear un alcance secundario en el nivel de actividad.

public class MyActivity { private ObjectGraph mGraph; public void onCreate() { mGraph = ((MyApp) getApplicationContext()) .getObjectGraph() .plus(new ActivityModule()) .inject(this); } public void onDestroy() { mGraph = null; } }

El ámbito secundario existió siempre que mantuviera una referencia a él, que en este caso fue el ciclo de vida de su Actividad. Dejar caer la referencia en onDestroy aseguró que el gráfico de alcance fuera libre para ser recolectado.

EDITAR

Jesse Wilson recientemente publicó un mea culpa

Dagger 1.0 jodió mal sus nombres de alcance ... La anotación @Singleton se usa tanto para gráficos raíz como para gráficos personalizados, por lo que es difícil determinar cuál es el alcance real de una cosa.

y todo lo demás que he leído / escuchado apunta a Dagger 2 mejorando la forma en que funcionan los ámbitos, pero me cuesta entender la diferencia. Según el comentario de @Kirill Boyarshinov a continuación, el ciclo de vida de un componente o dependencia aún está determinado, como de costumbre, por referencias concretas. Entonces, ¿la diferencia entre los alcances Dagger 1.xy 2.0 es puramente una cuestión de claridad semántica?

Mi punto de vista

Daga 1.x

Las dependencias eran @Singleton o no. Esto fue igualmente cierto para las dependencias en el gráfico raíz y los subgrafos, lo que lleva a la ambigüedad en cuanto a qué gráfico estaba vinculada la dependencia (ver En Dagger son Singletons dentro del sub-gráfico en caché o siempre se recrearán cuando una nueva sub-gráfica de actividad está construido? )

Daga 2.0

Los ámbitos personalizados le permiten crear ámbitos semánticamente claros, pero son funcionalmente equivalentes a la aplicación de @Singleton en Dagger 1.x.

// Application level @Singleton @Component( modules = MyAppModule.class ) public interface MyAppComponent { void inject(Application app); } @Module public class MyAppModule { @Singleton @Named("SingletonScope") @Provides StringBuilder provideStringBuilderSingletonScope() { return new StringBuilder("App"); } }

// Our custom scope @Scope public @interface PerActivity {}

// Activity level @PerActivty @Component( dependencies = MyAppComponent.class, modules = MyActivityModule.class ) public interface MyActivityComponent { void inject(Activity activity); } @Module public class MyActivityModule { @PerActivity @Named("ActivityScope") @Provides StringBuilder provideStringBuilderActivityScope() { return new StringBuilder("Activity"); } @Name("Unscoped") @Provides StringBuilder provideStringBuilderUnscoped() { return new StringBuilder("Unscoped"); } }

// Finally, a sample Activity which gets injected public class MyActivity { private MyActivityComponent component; @Inject @Named("AppScope") StringBuilder appScope @Inject @Named("ActivityScope") StringBuilder activityScope1 @Inject @Named("ActivityScope") StringBuilder activityScope2 @Inject @Named("Unscoped") StringBuilder unscoped1 @Inject @Named("Unscoped") StringBuilder unscoped2 public void onCreate() { component = Dagger_MyActivityComponent.builder() .myApplicationComponent(App.getComponent()) .build() .inject(this); appScope.append(" > Activity") appScope.build() // output matches "App (> Activity)+" activityScope1.append("123") activityScope1.build() // output: "Activity123" activityScope2.append("456") activityScope1.build() // output: "Activity123456" unscoped1.append("123") unscoped1.build() // output: "Unscoped123" unscoped2.append("456") unscoped2.build() // output: "Unscoped456" } public void onDestroy() { component = null; } }

La @PerActivity es que el uso de @PerActivity comunica su intención con respecto al ciclo de vida de este componente, pero en última instancia, puede usar el componente en cualquier lugar / en cualquier momento. La única promesa de Dagger es que, para un componente dado, los métodos anotados en el alcance devolverán una sola instancia. También supongo que Dagger 2 usa la anotación de alcance en el componente para verificar que los módulos solo proporcionen dependencias que estén en el mismo alcance o sin alcance.

En resumen

Las dependencias siguen siendo singleton o no singleton, pero @Singleton ahora está destinado a instancias de singleton a nivel de aplicación y los ámbitos personalizados son el método preferido para anotar dependencias de singleton con un ciclo de vida más corto.

El desarrollador es responsable de administrar el ciclo de vida de los componentes / dependencias eliminando referencias que ya no son necesarias y responsable de garantizar que los componentes solo se creen una vez en el alcance para el que están destinados, pero las anotaciones de alcance personalizadas hacen que sea más fácil identificar ese alcance .

La pregunta de $ 64k *

¿Es correcto mi comprensión de los ámbitos y ciclos de vida de Dagger 2?

* No es realmente una pregunta de $ 64,000.


En cuanto a su pregunta

¿Qué determina el ciclo de vida de un componente (gráfico de objeto) en Dagger 2?

La respuesta corta es que tú lo determinas . Sus componentes pueden tener un alcance, como

@Scope @Retention(RetentionPolicy.RUNTIME) public @interface ApplicationScope { } @Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { }

Estos son útiles para usted por dos cosas:

  • Validación del alcance: un componente solo puede tener proveedores sin alcance o proveedores con alcance del mismo alcance que su componente.

.

@Component(modules={ApplicationModule.class}) @ApplicationScope public interface ApplicationComponent { Something something(); AnotherThing anotherThing(); void inject(Whatever whatever); } @Module public class ApplicationModule { @ApplicationScope //application-scoped provider, only one can exist per component @Provides public Something something() { return new Something(); } @Provides //unscoped, each INJECT call creates a new instance public AnotherThing anotherThing() { return new AnotherThing(); } }

  • Permite sub-ámbito de sus dependencias de ámbito, lo que le permite crear un componente "sub-ámbito" que utiliza las instancias proporcionadas desde el componente "super-ámbito".

Esto se puede hacer con la anotación @Subcomponent o las dependencias de los componentes. Personalmente prefiero las dependencias.

@Component(modules={ApplicationModule.class}) @ApplicationScope public interface ApplicationComponent { Something something(); AnotherThing anotherThing(); void inject(Whatever whatever); ActivityComponent newActivityComponent(ActivityModule activityModule); //subcomponent factory method } @Subcomponent(modules={ActivityModule.class}) @ActivityScope public interface ActivityComponent { ThirdThingy thirdThingy(); void inject(SomeActivity someActivity); } @Module public class ActivityModule { private Activity activity; public ActivityModule(Activity activity) { this.activity = activity; } //... } ApplicationComponent applicationComponent = DaggerApplicationComponent.create(); ActivityComponent activityComponent = applicationComponent.newActivityComponent(new ActivityModule(SomeActivity.this));

O puede usar dependencias de componentes de esta manera

@Component(modules={ApplicationModule.class}) @ApplicationScope public class ApplicationComponent { Something something(); AnotherThing anotherThing(); void inject(Whatever whatever); } @Component(dependencies={ApplicationComponent.class}, modules={ActivityModule.class}) @ActivityScope public interface ActivityComponent extends ApplicationComponent { ThirdThingy thirdThingy(); void inject(SomeActivity someActivity); } @Module public class ActivityModule { private Activity activity; public ActivityModule(Activity activity) { this.activity = activity; } //... } ApplicationComponent applicationComponent = DaggerApplicationComponent.create(); ActivityComponent activityComponent = DaggerActivityComponent.builder().activityModule(new ActivityModule(SomeActivity.this)).build();

Cosas importantes a saber:

  • Un proveedor con ámbito crea una instancia para ese ámbito dado para cada componente . Lo que significa que un componente realiza un seguimiento de sus propias instancias, pero otros componentes no tienen un grupo de alcance compartido o algo de magia. Para tener una instancia en un ámbito determinado, necesita una instancia del componente. Es por eso que debe proporcionar ApplicationComponent para acceder a sus propias dependencias con ámbito.

  • Un componente puede subscope solo un componente de ámbito. No se permiten dependencias de componentes de ámbito múltiple.