course component android android-activity scope dagger-2

android - course - dagger 2 component



Áreas personalizadas de Dagger2: ¿Cómo funcionan realmente los ámbitos personalizados(@ActivityScope)? (2)

En realidad no hay magia. Las anotaciones de alcance personal son solo anotaciones. Ellos pueden tener cualquier nombre. Las anotaciones de ámbito sirven como una herramienta para el análisis estático de las dependencias que los módulos proporcionan y los componentes inyectados. Es por eso que el uso de la dependencia de @ActivityScope componente que no es de @ActivityScope generará un error de compilación.

Cómo definir el alcance real es su prerrogativa. Defina el ciclo de vida de su componente de alcance, a qué hora se creó y a qué hora se destruyó: este es su alcance. Por ejemplo, @ActivityScope está relacionado con el ciclo de vida de la actividad y se define así:

private ActivityComponent component; @Override protected void onCreate(Bundle savedInstanceState) { component = DaggerActivityComponent.builder().build(); component.inject(this); } @Override protected void onDestroy() { component = null; super.onDestroy(); }

Entonces no hay magia. Defina sus ámbitos por la semántica de usarlos. También puede ser útil esta respuesta y estos ejemplos .

Estoy leyendo el código fuente para Dagger2 Component Scopes Test en GitHub, y he visto un "alcance personalizado" definido para actividades llamado @ActivityScope , pero lo he visto en otros proyectos, incluyendo el CleanArchitecture 4 módulos que tiene su @PerActivity Alcance de la actividad

Pero, literalmente, el código para la anotación @ActivityScope es el siguiente:

import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import javax.inject.Scope; /** * Created by joesteele on 2/15/15. */ @Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActivityScope { }

Y es "mágicamente" utilizable en los módulos:

@Module public class ActivityModule { @Provides @ActivityScope Picasso providePicasso(ComponentTest app, OkHttpClient client) { return new Picasso.Builder(app) .downloader(new OkHttpDownloader(client)) .listener(new Picasso.Listener() { @Override public void onImageLoadFailed(Picasso picasso, Uri uri, Exception e) { Log.e("Picasso", "Failed to load image: " + uri.toString(), e); } }) .build(); } }

O el ejemplo de CleanArchitecture :

@Scope @Retention(RUNTIME) public @interface PerActivity {} @PerActivity @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { //Exposed to sub-graphs. Activity activity(); } @Module public class ActivityModule { private final Activity activity; public ActivityModule(Activity activity) { this.activity = activity; } /** * Expose the activity to dependents in the graph. */ @Provides @PerActivity Activity activity() { return this.activity; } }

Puedo ver claramente que esto tiene que ver con los ámbitos personalizados JSR-330, pero realmente no entiendo qué está sucediendo exactamente aquí para que este código habilite el módulo dado y / o lo que proporciona un módulo dado a Depende del ciclo de vida real de la Activity , y de que exista solo una instancia única, pero solo si esa actividad dada está activa.

Los documentos dicen esto:

Scope Dagger 1 only supported a single scope: @Singleton. Dagger 2 allows users to any well-formed scope annotation. The Component docs describe the details of how to properly apply scope to a component.

Dice que mire la página Documentos de componentes , pero eso me da 404. También vi this , pero ...

¿Puedo pedir ayuda para aclarar por qué la especificación de este ámbito personalizado hace mágicamente que Activity-level scopes funcionen sin problemas?

(La respuesta es que un subámbito puede recibir dependencias de su superámbito, y existe un subámbito siempre que lo haga el componente, y que debe especificar los ámbitos en sus módulos, y debe especificar las dependencias de sus componentes para que sean un subámbito. )


Vale la pena señalar que aparentemente Dagger2 crea una sola instancia por proveedor con ámbito en un módulo por componente.

Por lo tanto, para obtener un proveedor de ámbito en un módulo, debe especificar el alcance para el método de proveedor de su módulo.

@Module public class YourModule { @Provides @YourScope //one per component public Something something() { return new SomethingImpl(); } @Provides //new instance per injection public Otherthing otherthing() { return new OtherthingImpl(); } } @Component @YourScope public interface YourComponent { Something something(); Otherthing otherthing(); void inject(YourThing yourThing); }

Luego, refiérase a la respuesta de Kirill; esencialmente un "alcance" por sí solo solo determina que es un ámbito diferente del otro. El uso de dependencias de componentes (o subcomponentes) crea un subámbito.

@Module public class SubModule { @Provides @SubScope public ThatThing thatThing() { return new ThatThingImpl(); } } @Component(dependencies={YourComponent.class}, modules={SubModule.class}) @SubScope public interface SubComponent extends YourComponent { ThatThing thatThing(); void inject(SubThing subThing); }

Un componente puede depender solo de otro componente con ámbito.