Guía para Dagger 2.x (Edición revisada 6) :
Los pasos son los siguientes:
1.) agregar Dagger
a sus build.gradle
archivos:
- build.gradle de nivel superior :
.
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8' //added apt for source code generation
}
}
allprojects {
repositories {
jcenter()
}
}
- nivel de aplicación build.gradle :
.
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt' //needed for source code generation
android {
compileSdkVersion 24
buildToolsVersion "24.0.2"
defaultConfig {
applicationId "your.app.id"
minSdkVersion 14
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
debug {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
apt 'com.google.dagger:dagger-compiler:2.7' //needed for source code generation
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:24.2.1'
compile 'com.google.dagger:dagger:2.7' //dagger itself
provided 'org.glassfish:javax.annotation:10.0-b28' //needed to resolve compilation errors, thanks to tutplus.org for finding the dependency
}
2.) Cree su AppContextModule
clase que proporciona las dependencias.
@Module //a module could also include other modules
public class AppContextModule {
private final CustomApplication application;
public AppContextModule(CustomApplication application) {
this.application = application;
}
@Provides
public CustomApplication application() {
return this.application;
}
@Provides
public Context applicationContext() {
return this.application;
}
@Provides
public LocationManager locationService(Context context) {
return (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
}
}
3.) crea la AppContextComponent
clase que proporciona la interfaz para obtener las clases que son inyectables.
public interface AppContextComponent {
CustomApplication application(); //provision method
Context applicationContext(); //provision method
LocationManager locationManager(); //provision method
}
3.1.) Así es como crearía un módulo con una implementación:
@Module //this is to show that you can include modules to one another
public class AnotherModule {
@Provides
@Singleton
public AnotherClass anotherClass() {
return new AnotherClassImpl();
}
}
@Module(includes=AnotherModule.class) //this is to show that you can include modules to one another
public class OtherModule {
@Provides
@Singleton
public OtherClass otherClass(AnotherClass anotherClass) {
return new OtherClassImpl(anotherClass);
}
}
public interface AnotherComponent {
AnotherClass anotherClass();
}
public interface OtherComponent extends AnotherComponent {
OtherClass otherClass();
}
@Component(modules={OtherModule.class})
@Singleton
public interface ApplicationComponent extends OtherComponent {
void inject(MainActivity mainActivity);
}
Tenga cuidado: debe proporcionar la @Scope
anotación (como @Singleton
o @ActivityScope
) en el @Provides
método anotado del módulo para obtener un proveedor con ámbito dentro de su componente generado; de lo contrario, no tendrá ámbito y obtendrá una nueva instancia cada vez que inyecte.
3.2.) Cree un componente de ámbito de aplicación que especifique lo que puede inyectar (esto es lo mismo que injects={MainActivity.class}
en Dagger 1.x):
@Singleton
@Component(module={AppContextModule.class}) //this is where you would add additional modules, and a dependency if you want to subscope
public interface ApplicationComponent extends AppContextComponent { //extend to have the provision methods
void inject(MainActivity mainActivity);
}
3.3.) Para las dependencias que puede crear a través de un constructor usted mismo y no querrá redefinir usando un @Module
(por ejemplo, usa build flavors en su lugar para cambiar el tipo de implementación), puede usar un @Inject
constructor anotado.
public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
Además, si usa el @Inject
constructor, puede usar la inyección de campo sin tener que llamar explícitamente component.inject(this)
:
public class Something {
@Inject
OtherThing otherThing;
@Inject
public Something() {
}
}
Estas @Inject
clases de constructor se agregan automáticamente al componente del mismo ámbito sin tener que especificarlas explícitamente en un módulo.
Una clase de constructor con @Singleton
ámbito @Inject
se verá en @Singleton
componentes con ámbito.
@Singleton // scoping
public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
3.4.) Después de haber definido una implementación específica para una interfaz determinada, así:
public interface Something {
void doSomething();
}
@Singleton
public class SomethingImpl {
@Inject
AnotherThing anotherThing;
@Inject
public SomethingImpl() {
}
}
Deberá "vincular" la implementación específica a la interfaz con un @Module
.
@Module
public class SomethingModule {
@Provides
Something something(SomethingImpl something) {
return something;
}
}
Un resumen de esto desde Dagger 2.4 es el siguiente:
@Module
public abstract class SomethingModule {
@Binds
abstract Something something(SomethingImpl something);
}
4.) cree una Injector
clase para manejar su componente de nivel de aplicación (reemplaza al monolítico ObjectGraph
)
(nota: Rebuild Project
para crear la DaggerApplicationComponent
clase de constructor usando APT)
public enum Injector {
INSTANCE;
ApplicationComponent applicationComponent;
private Injector(){
}
static void initialize(CustomApplication customApplication) {
ApplicationComponent applicationComponent = DaggerApplicationComponent.builder()
.appContextModule(new AppContextModule(customApplication))
.build();
INSTANCE.applicationComponent = applicationComponent;
}
public static ApplicationComponent get() {
return INSTANCE.applicationComponent;
}
}
5.) crea tu CustomApplication
clase
public class CustomApplication
extends Application {
@Override
public void onCreate() {
super.onCreate();
Injector.initialize(this);
}
}
6.) agregar CustomApplication
a su AndroidManifest.xml
.
<application
android:name=".CustomApplication"
...
7.) Inyecta tus clases enMainActivity
public class MainActivity
extends AppCompatActivity {
@Inject
CustomApplication customApplication;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Injector.get().inject(this);
//customApplication is injected from component
}
}
8.) ¡Disfruta!
+1.) Puede especificar Scope
para sus componentes con los que puede crear componentes con ámbito de nivel de actividad . Los subámbitos le permiten proporcionar dependencias que solo necesita para un subámbito determinado, en lugar de para toda la aplicación. Normalmente, cada actividad tiene su propio módulo con esta configuración. Tenga en cuenta que existe un proveedor de ámbito por componente , lo que significa que para retener la instancia para esa actividad, el componente en sí debe sobrevivir al cambio de configuración. Por ejemplo, podría sobrevivir a través de onRetainCustomNonConfigurationInstance()
un alcance de mortero.
Para obtener más información sobre el subámbito, consulte la guía de Google . También consulte este sitio sobre métodos de provisión y también la sección de dependencias de componentes ) y aquí .
Para crear un alcance personalizado, debe especificar la anotación de calificador de alcance:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface YourCustomScope {
}
Para crear un subámbito, debe especificar el ámbito de su componente y especificarlo ApplicationComponent
como su dependencia. Obviamente, también debe especificar el subámbito en los métodos del proveedor del módulo.
@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
Y
@Module
public class CustomScopeModule {
@Provides
@YourCustomScope
public CustomScopeClass customScopeClass() {
return new CustomScopeClassImpl();
}
}
Tenga en cuenta que sólo un componente restringidos se puede especificar como una dependencia. Piense en ello exactamente como en Java no se admite la herencia múltiple.
+2.) Acerca de @Subcomponent
: esencialmente, un ámbito @Subcomponent
puede reemplazar la dependencia de un componente; pero en lugar de utilizar un constructor proporcionado por el procesador de anotaciones, necesitaría utilizar un método de fábrica de componentes.
Así que esto:
@Singleton
@Component
public interface ApplicationComponent {
}
@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
Se convierte en esto:
@Singleton
@Component
public interface ApplicationComponent {
YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule);
}
@Subcomponent(modules={CustomScopeModule.class})
@YourCustomScope
public interface YourCustomScopedComponent {
CustomScopeClass customScopeClass();
}
Y esto:
DaggerYourCustomScopedComponent.builder()
.applicationComponent(Injector.get())
.customScopeModule(new CustomScopeModule())
.build();
Se convierte en esto:
Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule());
+3.): Consulte también otras preguntas de Stack Overflow sobre Dagger2, ya que proporcionan mucha información. Por ejemplo, mi estructura actual de Dagger2 se especifica en esta respuesta .
Gracias
Gracias por las guías de Github , TutsPlus , Joe Steele , Froger MCS y Google .
También para esta guía de migración paso a paso que encontré después de escribir esta publicación.
Y para la explicación del alcance de Kirill.
Aún más información en la documentación oficial .