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.