Guida per Dagger 2.x (edizione rivista 6) :
I passaggi sono i seguenti:
1.) aggiungi Dagger
ai tuoi build.gradle
file:
- build.gradle di primo livello :
.
// 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()
}
}
- livello di app 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.) Crea la tua AppContextModule
classe che fornisce le dipendenze.
@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.) creare la AppContextComponent
classe che fornisce l'interfaccia per ottenere le classi iniettabili.
public interface AppContextComponent {
CustomApplication application(); //provision method
Context applicationContext(); //provision method
LocationManager locationManager(); //provision method
}
3.1.) Ecco come creeresti un modulo con un'implementazione:
@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);
}
Attenzione: è necessario fornire l' @Scope
annotazione (come @Singleton
o @ActivityScope
) sul @Provides
metodo annotato del modulo per ottenere un provider con ambito all'interno del componente generato, altrimenti sarà privo di ambito e riceverai una nuova istanza ogni volta che inietti.
3.2.) Creare un componente con ambito applicazione che specifichi cosa è possibile iniettare (questo è lo stesso injects={MainActivity.class}
di 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.) Per le dipendenze che puoi creare tu stesso tramite un costruttore e non vorrai ridefinirle usando a @Module
(ad esempio, usi i gusti di compilazione invece di cambiare il tipo di implementazione), puoi usare il @Inject
costruttore annotato.
public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
Inoltre, se usi il @Inject
costruttore, puoi usare l'iniezione di campi senza dover chiamare esplicitamente component.inject(this)
:
public class Something {
@Inject
OtherThing otherThing;
@Inject
public Something() {
}
}
Queste @Inject
classi del costruttore vengono aggiunte automaticamente al componente dello stesso ambito senza doverle specificare esplicitamente in un modulo.
Una classe di costruttore con @Singleton
ambito @Inject
verrà visualizzata nei @Singleton
componenti con ambito.
@Singleton // scoping
public class Something {
OtherThing otherThing;
@Inject
public Something(OtherThing otherThing) {
this.otherThing = otherThing;
}
}
3.4.) Dopo aver definito un'implementazione specifica per una data interfaccia, in questo modo:
public interface Something {
void doSomething();
}
@Singleton
public class SomethingImpl {
@Inject
AnotherThing anotherThing;
@Inject
public SomethingImpl() {
}
}
Dovrai "associare" l'implementazione specifica all'interfaccia con un file @Module
.
@Module
public class SomethingModule {
@Provides
Something something(SomethingImpl something) {
return something;
}
}
Un'abbreviazione per questo dato che Dagger 2.4 è la seguente:
@Module
public abstract class SomethingModule {
@Binds
abstract Something something(SomethingImpl something);
}
4.) crea una Injector
classe per gestire il tuo componente a livello di applicazione (sostituisce il monolitico ObjectGraph
)
(nota: Rebuild Project
per creare la DaggerApplicationComponent
classe builder utilizzando 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 la tua CustomApplication
classe
public class CustomApplication
extends Application {
@Override
public void onCreate() {
super.onCreate();
Injector.initialize(this);
}
}
6.) aggiungi CustomApplication
al tuo AndroidManifest.xml
.
<application
android:name=".CustomApplication"
...
7.) Inietta le tue classiMainActivity
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.) Buon divertimento!
+1.) È possibile specificare Scope
per i componenti con cui creare componenti con ambito a livello di attività . Gli ambiti secondari consentono di fornire le dipendenze necessarie solo per un determinato ambito secondario, piuttosto che per l'intera applicazione. In genere, ogni attività riceve il proprio modulo con questa configurazione. Si noti che esiste un provider con ambito per componente , il che significa che per mantenere l'istanza per tale attività, il componente stesso deve sopravvivere alla modifica della configurazione. Ad esempio, potrebbe sopravvivere attraverso onRetainCustomNonConfigurationInstance()
, o un mirino di mortaio.
Per maggiori informazioni sull'abbonamento, consulta la guida di Google . Si prega inoltre di consultare questo sito sui metodi di fornitura e anche la sezione delle dipendenze dei componenti ) e qui .
Per creare un ambito personalizzato, è necessario specificare l'annotazione del qualificatore dell'ambito:
@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface YourCustomScope {
}
Per creare un ambito secondario, è necessario specificare l'ambito sul componente e specificarlo ApplicationComponent
come sua dipendenza. Ovviamente è necessario specificare anche l'ambito secondario sui metodi del provider del modulo.
@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
E
@Module
public class CustomScopeModule {
@Provides
@YourCustomScope
public CustomScopeClass customScopeClass() {
return new CustomScopeClassImpl();
}
}
Si noti che solo un componente con ambito può essere specificato come dipendenza. Pensa esattamente allo stesso modo in cui l'ereditarietà multipla non è supportata in Java.
+2.) Informazioni su @Subcomponent
: essenzialmente, uno scoped @Subcomponent
può sostituire una dipendenza del componente; ma invece di usare un builder fornito dal processore di annotazioni, dovresti usare un metodo di fabbrica dei componenti.
Così questo:
@Singleton
@Component
public interface ApplicationComponent {
}
@YourCustomScope
@Component(dependencies = {ApplicationComponent.class}, modules = {CustomScopeModule.class})
public interface YourCustomScopedComponent
extends ApplicationComponent {
CustomScopeClass customScopeClass();
void inject(YourScopedClass scopedClass);
}
Diventa questo:
@Singleton
@Component
public interface ApplicationComponent {
YourCustomScopedComponent newYourCustomScopedComponent(CustomScopeModule customScopeModule);
}
@Subcomponent(modules={CustomScopeModule.class})
@YourCustomScope
public interface YourCustomScopedComponent {
CustomScopeClass customScopeClass();
}
E questo:
DaggerYourCustomScopedComponent.builder()
.applicationComponent(Injector.get())
.customScopeModule(new CustomScopeModule())
.build();
Diventa questo:
Injector.INSTANCE.newYourCustomScopedComponent(new CustomScopeModule());
+3.): Controlla anche altre domande su Stack Overflow riguardanti Dagger2, che forniscono molte informazioni. Ad esempio, la mia attuale struttura Dagger2 è specificata in questa risposta .
Grazie
Grazie per le guide su Github , TutsPlus , Joe Steele , Froger MCS e Google .
Anche per questa guida passo passo alla migrazione che ho trovato dopo aver scritto questo post.
E per la spiegazione dell'ambito di Kirill.
Ancora più informazioni nella documentazione ufficiale .