Dagger2 enthält dagger.android ab 2.10 und 2.11 macht die Verwendung noch einfacher. Hier ist ein Blick auf den generierten Code und eine Beschreibung dessen, was er tut. Übrigens werde ich auch beschreiben, wie man mit Android-Unterstützung in Kotlin installiert.
Gradle
build.gradle
buildscript {
ext.dagger_version = "2.12"
・ ・ ・
app/build.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
・ ・ ・
dependencies {
・ ・ ・
kapt "com.google.dagger:dagger-compiler:$dagger_version"
kapt "com.google.dagger:dagger-android-processor:$dagger_version"
implementation "com.google.dagger:dagger:$dagger_version"
implementation "com.google.dagger:dagger-android:$dagger_version"
・ ・ ・
Module
Im Folgenden erfahren Sie, wie Sie das im Android-Support hinzugefügte Modul schreiben.
AndroidModule.kt
@Module
abstract class AndroidModule {
@ContributesAndroidInjector
abstract fun contributeMainActivity(): MainActivity
}
@ContributesAndroidInjector ist 2.Es ist eine API aus 11.
Dadurch wird der Code generiert, den Sie in 2.10 geschrieben haben.
Die automatisch generierte Quelle wird später erläutert.
Component
#### **`AppComponent.kt`**
```kt
@Singleton
@Component(modules = arrayOf(AndroidInjectionModule::class, AndroidModule::class))
interface AppComponent {
@Component.Builder
interface Builder {
@BindsInstance
fun application(application: App): Builder
fun build(): AppComponent
}
fun inject(app: App)
}
AndroidInjectionModule::Klasse ist Miso. 2.Hinzugefügt von 10.
#### **`@BindsInstance ist 2.Hinzugefügt von 9. Wenn Sie eine eigene Komponente erstellen, können Sie der Komponente Argumente hinzufügen, indem Sie die Methode aufrufen, die sie angibt.`**
```Hinzugefügt von 9. Wenn Sie eine eigene Komponente erstellen, können Sie der Komponente Argumente hinzufügen, indem Sie die Methode aufrufen, die sie angibt.
Dies bedeutet, dass Sie einen Kompilierungsfehler erhalten, wenn Sie nicht `` `@BindsInstance fun application (application: App): Builder``` schreiben, wenn Sie beispielsweise versuchen, den Kontext wie unten gezeigt einzufügen.
@Module class AppModule { @Provides fun provideContext(application: App) = application.applicationContext }
class MainDao @Inject constructor() { @Inject lateinit var context: Context
#### **`@BindsInstance fun application(application: App):Durch Beschreiben des Builders und Festlegen in der Application-Klasse kann er im DI-Status des Moduls verwendet werden.`**
Application
Erstellen Sie die Komponente mit der Klasse `` `DaggerAppComponent```, die automatisch aus AppComponent generiert wird.
App.kt
class App : Application(), HasActivityInjector {
@Inject lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>
override fun activityInjector() = dispatchingAndroidInjector
override fun onCreate() {
super.onCreate()
val objectGraph = DaggerAppComponent
.builder()
.application(this)
.build()
objectGraph.inject(this)
}
}
Die App-Klasse wird im Modul mithilfe der in AppComponent angegebenen Methode `@ BindsInstance``` verfügbar gemacht. (Dies ist der Teil von
application (this)
.) Auch die Schnittstelle ``
dagger.android.HasActivityInjector``` ist wichtig. Dies wird anhand der folgenden Aktivitätsquelle erläutert.
Activity
Dank der Android-Unterstützung können Sie jetzt einfach `dagger.android.AndroidInjection.inject (this)`
schreiben und es wird DI sein.
MainActivity.kt
lass MainActivity : AppCompatActivity() {
@Inject
lateinit var viewModel: MainViewModel
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
・ ・ ・
Ich werde auch andere Klassen posten.
MainViewModel.kt
class MainViewModel @Inject constructor() {
@Inject
lateinit var domain: MainDomain
・ ・ ・
dagger.android.AndroidInjection.inject(this)Was speziell getan wird, ist die Anwendungsklasse(App in diesem Fall.kt Klasse)Mit Dolch.android.Wenn HasActivityInjector implementiert ist, Dolch.android.Argumentaktivität mit DispatchingAndroidInjector(Hier ist MainActivity)Componet(Dies ist eine Klasse zum Auflösen von Abhängigkeiten. Auch als ObjectGraph bekannt.)Ich habe es reingelegt. ((@Wenn Sie ContributesAndroidInjector nicht schreiben, wird hier ein Assert-Fehler angezeigt. )
Dann wird es in das Feld "@ Inject" in Activity injiziert.
Insbesondere ist "dagger.android.DispatchingAndroidInjector" der Code "MainActivitySubcomponentBuilder", der automatisch von "@ ContributesAndroidInjector" generiert wird und im Modul mit "MainActivity" als Schlüssel definiert ist. Builder generiert auch die automatisch generierte Klasse `` `MainActivitySubcomponentImpl``` (die Implementierungsklasse von` `` dagger.android.AndroidInjector```), die jede Klasse injiziert.
Unten ist ein Teil des entsprechenden Codes beschrieben.
Die folgende mayInject-Methode befindet sich, bevor AndroidInjection.inject (this) of Activity aufgerufen wird.
#### **`dagger.android.DispatchingAndroidInjector.java`**
public boolean maybeInject(T instance) { // ① instance=MainActivity Provider<AndroidInjector.Factory<? extends T>> factoryProvider = injectorFactories.get(instance.getClass()); if (factoryProvider == null) { return false; }
@SuppressWarnings("unchecked")
AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get(); // ② factory=MainActivitySubcomponentBuilder
try {
AndroidInjector<T> injector =
checkNotNull(
factory.create(instance), // ③ new MainActivitySubcomponentImpl()
"%s.create(I) should not return null.",
factory.getClass().getCanonicalName());
injector.inject(instance); // ④
Das Argument `` `T instance``` in Zeile ① ist MainActivity.
MainActivitySubcomponentBuilder wird in `` `AndroidInjector.Factory <T> factory``` in Zeile ② eingegeben.
MainActivitySubcomponentImpl wird mit `` `factory.create (instance)` `` in Zeile instant instanziiert.
In Zeile ④ `` `jektor.inject (Instanz); `` `wird der` `MembersInjector <MainActivity>` `` von der automatisch generierten `` `DaggerAppComponent``` (ebenfalls automatisch generiert) gehalten. `` `MainActivity_MembersInjector``` ist die Implementierungsklasse) wird verwendet, um die Klasse in MainActivity auf DI zu setzen.
# Automatisch generierter Code
```@contributesandroidinjector```Der von generierte Code ist unten.
In Version 2.10 mussten Sie dies selbst schreiben.
#### **`AndroidModule_ContributeMainActivity.java`**
```java
@Module(subcomponents = AndroidModule_ContributeMainActivity.MainActivitySubcomponent.class)
public abstract class AndroidModule_ContributeMainActivity {
private AndroidModule_ContributeMainActivity() {}
@Binds
@IntoMap
@ActivityKey(MainActivity.class)
abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
MainActivitySubcomponent.Builder builder);
@Subcomponent
public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
@Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<MainActivity> {} // implemenets AndroidInjector.Factory
}
}
@binds
Ist eine Anmerkung, die Sie davon abhält, den folgenden Standardcode auf sehr einfache Weise zu schreiben.
@Provides
AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(){
return new MainActivitySubcomponent.Builder()
}
Tatsächlich ist `` `MainActivitySubcomponent.Builder``` auch abstrakt, so dass Sie die erforderlichen Methoden implementieren müssen, aber genau das ist es.
@Mit IntoMap@ActivityKey wird als Set verwendet. Der hier angegebene ist Dolch.android.Es wird eine Karte sein, die von DispatchingAndroidInjector gehalten wird.(Diese Karte wird am Ende wichtig sein)
#### **`@Der von ActivityKey angegebene Wert (in diesem Fall MainActivity).Klasse) ist der Schlüssel. Der Wert ist der Rückgabewert der Methode (in diesem Fall MainActivitySubcomponent)..Werde ein Baumeister. Dieser Builder ist übrigens ein Android Injector.Es wird eine Implementierung von Factory sein.`**
Das Folgende ist der Zielteil, der automatisch aus AppComponent generiert wird.
DaggerAppComponent.java
・ ・ ・
private Provider<AndroidInjector.Factory<? extends Activity>> bindAndroidInjectorFactoryProvider;
・ ・ ・
@Override
public AppComponent build() {
if (application == null) {
throw new IllegalStateException(App.class.getCanonicalName() + " must be set");
}
return new DaggerAppComponent(this);
}
・ ・ ・
private DaggerAppComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.mainActivitySubcomponentBuilderProvider =
new dagger.internal.Factory<
AndroidModule_ContributeMainActivity.MainActivitySubcomponent.Builder>() {
@Override
public AndroidModule_ContributeMainActivity.MainActivitySubcomponent.Builder get() {
return new MainActivitySubcomponentBuilder();
}
}; //drei
this.bindAndroidInjectorFactoryProvider = (Provider) mainActivitySubcomponentBuilderProvider; //Zwei
this.mapOfClassOfAndProviderOfFactoryOfProvider =
MapProviderFactory
.<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>builder(1)
.put(MainActivity.class, bindAndroidInjectorFactoryProvider)
.build(); //Ichi bindAndroidInjectorFactoryProvider=dagger.internal.Factory()Anonyme Klasse von Geräten Anbieter. Über 2,Schau Schau
this.dispatchingAndroidInjectorProvider =
DispatchingAndroidInjector_Factory.create(mapOfClassOfAndProviderOfFactoryOfProvider);
this.appMembersInjector = App_MembersInjector.create(dispatchingAndroidInjectorProvider);
}
・ ・ ・
Werfen wir einen konkreten Blick auf die "Map of MainActivity.class ist der Schlüssel und der Wert ist MainActivitySubcomponent.Builder", die ich als wichtig erklärt habe. Der im Kartenwert von Ichi angegebene bindAndroidInjectorFactoryProvider ist Wenn Sie sich die zweite ansehen, wird sie zum mainActivitySubcomponentBuilderProvider. Darüber hinaus ist mainActivitySubcomponentBuilderProvider eine anonyme Klasse von `` `dagger.internal.Factory```.
dagger.internal.Fabrik ist Javax.inject.Die Instanz, die von Provider erbt und von get zurückgegeben wird, ist die MainActivitySubcomponentBuilder-Klasse.
#### **`Die übergeordnete Klasse von MainActivitySubcomponentBuilder ist MainActivitySubcomponent.Werde ein Baumeister.`**
```Werde ein Baumeister.
Übrigens, in Dagger kann der Provider DI-Ziel sein, wenn die Klasse, die durch `` `javax.inject.Provider # get ()` `` erhalten werden kann, injiziert werden kann.
Mit anderen Worten ist die folgende Definition nicht erforderlich.
@Provides
fun provideMainActivitySubcomponentBuilderProvider() = object: Provider
Daher lautet der Schlüssel MainActivity und der Wert `` `Provider <AndroidInjector.Factory <? Extends Activity >>` ``.
Es ist eine Fortsetzung. Es ist eine Fortsetzung von DaggerAppComponent.java.
#### **`DaggerAppComponent.java`**
```java
private final class MainActivitySubcomponentBuilder
extends AndroidModule_ContributeMainActivity.MainActivitySubcomponent.Builder {
private MainActivity seedInstance;
@Override
public AndroidModule_ContributeMainActivity.MainActivitySubcomponent build() {
if (seedInstance == null) {
throw new IllegalStateException(MainActivity.class.getCanonicalName() + " must be set");
}
return new MainActivitySubcomponentImpl(this); //"EIN"
}
@Override
public void seedInstance(MainActivity arg0) {
this.seedInstance = Preconditions.checkNotNull(arg0);
}
}
private final class MainActivitySubcomponentImpl
implements AndroidModule_ContributeMainActivity.MainActivitySubcomponent {
private MembersInjector<MainViewModel> mainViewModelMembersInjector;
private Provider<MainViewModel> mainViewModelProvider;
private MembersInjector<MainActivity> mainActivityMembersInjector;
private MainActivitySubcomponentImpl(MainActivitySubcomponentBuilder builder) {
assert builder != null;
initialize(builder);
}
@SuppressWarnings("unchecked")
private void initialize(final MainActivitySubcomponentBuilder builder) { //"ICH"
this.mainViewModelMembersInjector =
MainViewModel_MembersInjector.create(MainDomain_Factory.create());
this.mainViewModelProvider = MainViewModel_Factory.create(mainViewModelMembersInjector);
this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainViewModelProvider);
}
@Override
public void inject(MainActivity arg0) {
mainActivityMembersInjector.injectMembers(arg0); //"U"
}
}
MainActivitySubcomponent.Builder instanziiert MainActivitySubcomponentImpl mit "A".
Die eigentliche Instanz davon ist der Teil factory `factory.create (instance)`
, der in `` dagger.android.DispatchingAndroidInjector.java``` erklärt wird, was schließlich
`ist Es wird von "AndroidInjection.inject (this)" aufgerufen, das zu Beginn von "Activity # onCreate ()" "aufgerufen wird.
Wenn dann "MainActivitySubcomponentImpl" instanziiert wird, enthält die Methode von "A" den Provider der Klasse, die Sie mit "@ Inject" bearbeiten möchten. ~ Injector-Klasse wird automatisch in der Factory-Klasse generiert. Instanzieren Sie es und setzen Sie es in das Feld, das `` @ Inject``` der übergebenen Aktivität mit "U" beschreibt.
Der in "U" verwendete MainActivity_MembersInjector lautet wie folgt.
MainActivity_MembersInjector.java
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
private final Provider<MainViewModel> viewModelProvider;
public MainActivity_MembersInjector(Provider<MainViewModel> viewModelProvider) {
assert viewModelProvider != null;
this.viewModelProvider = viewModelProvider;
}
public static MembersInjector<MainActivity> create(Provider<MainViewModel> viewModelProvider) {
return new MainActivity_MembersInjector(viewModelProvider);
}
@Override
public void injectMembers(MainActivity instance) {
if (instance == null) {
throw new NullPointerException("Cannot inject members into a null reference");
}
instance.viewModel = viewModelProvider.get();
}
}
Oben ist die Instanz von viewModelProvider unten.
MainViewModel_Factory.java
public final class MainViewModel_Factory implements Factory<MainViewModel> {
private final MembersInjector<MainViewModel> mainViewModelMembersInjector;
public MainViewModel_Factory(MembersInjector<MainViewModel> mainViewModelMembersInjector) {
assert mainViewModelMembersInjector != null;
this.mainViewModelMembersInjector = mainViewModelMembersInjector;
}
@Override
public MainViewModel get() {
return MembersInjectors.injectMembers(mainViewModelMembersInjector, new MainViewModel());
}
public static Factory<MainViewModel> create(
MembersInjector<MainViewModel> mainViewModelMembersInjector) {
return new MainViewModel_Factory(mainViewModelMembersInjector);
}
}
@Singleton
Das Folgende führt zu `` `@ Singleton```.
@Module
class AppModule {
@Singleton
@Provides
fun provideMainDomain() = MainDomain()
}
@Singleton
class MainDomain @Inject constructor()
@Singleton
@Component(modules = arrayOf(AndroidInjectionModule::class, AndroidModule::class, AppModule::class))
interface AppComponent
・ ・ ・
Der Code auf der Benutzerseite ist wie gewohnt.
class MainViewModel @Inject constructor() {
@Inject
lateinit var domain: MainDomain
・ ・ ・
Mal sehen, was passiert, wenn wir das tun
Erstens, wenn Sie es nicht anhängen.
DaggerAppComponent.java
・ ・ ・
private final class MainActivitySubcomponentImpl
implements AndroidModule_ContributeMainActivity.MainActivitySubcomponent {
・ ・ ・
private void initialize(final MainActivitySubcomponentBuilder builder) {
this.mainViewModelMembersInjector =
MainViewModel_MembersInjector.create(MainDomain_Factory.create()); //Hier ist anders
・ ・ ・
Die Provider-Klasse von MainDomain lautet wie folgt. Diese Klasse existiert auch mit `` `@ Singleton```.
MainDomain_Factory.java
public final class MainDomain_Factory implements Factory<MainDomain> {
private static final MainDomain_Factory INSTANCE = new MainDomain_Factory();
@Override
public MainDomain get() {
return new MainDomain();
}
public static Factory<MainDomain> create() {
return INSTANCE;
}
}
mainviewmodel_membersinjector#create
Das an übergebene Argument ist maindomain_In der Fabrik wird es()Die Methode instanziiert und gibt die Hauptdomäne zurück. Fabrik=Im Provider wird es jedes Mal instanziiert, wenn get aufgerufen wird.
Das Folgende ist der Fall bei `` `@ Singleton.
mainviewmodel_membersinjector#create```Der Anbieter, an den weitergegeben werden soll, ist unterschiedlich.
DaggerAppComponent.java
this.mainViewModelMembersInjector =
MainViewModel_MembersInjector.create(DaggerAppComponent.this.provideMainDomainProvider); //Hier ist anders
public static AppComponent.Builder builder() {
return new Builder();
}
@SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
・ ・ ・
this.provideMainDomainProvider =
DoubleCheck.provider(AppModule_ProvideMainDomainFactory.create(builder.appModule));
Diese `DoubleCheck.provider ()`
Methode hält die MainDomain für Singleton im Feld `` instance``` und gibt sie zurück, wenn der MainDomainProvider aufgerufen wird.
DoubleCheck.java
public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
private static final Object UNINITIALIZED = new Object();
private volatile Provider<T> provider;
private volatile Object instance = UNINITIALIZED;
private DoubleCheck(Provider<T> provider) {
assert provider != null;
this.provider = provider;
}
@Override
public T get() {
Object result = instance;
if (result == UNINITIALIZED) {
synchronized (this) {
result = instance;
if (result == UNINITIALIZED) {
result = provider.get(); // provider=AppModule_ProvideMainDomainFactory. MainDomain wird hier instanziiert
Object currentInstance = instance;
if (currentInstance != UNINITIALIZED && currentInstance != result) {
throw new IllegalStateException("Scoped provider was invoked recursively returning "
+ "different results: " + currentInstance + " & " + result + ". This is likely "
+ "due to a circular dependency.");
}
instance = result; //Da MainDomain hier zwischengespeichert wird, wird bei jedem Aufruf dieselbe Instanz zurückgegeben.
provider = null;
}
}
}
return (T) result;
}
public static <T> Provider<T> provider(Provider<T> delegate) {
checkNotNull(delegate);
if (delegate instanceof DoubleCheck) {
return delegate;
}
return new DoubleCheck<T>(delegate); // App.Aufgerufen von kt
}
Die zwischengespeicherte DoubleCheck-Instanz wird übrigens von App.kt aufgerufen.
Für Aktivitäten usw. erhalten Sie eine Instanz aus dem Cache, indem Sie requireMainDomainProvider in `AndroidInjection.inject (this)`
verwenden.
Recommended Posts