[JAVA] Verstehen Sie, was die Android-Unterstützung von Dagger2 bewirkt

Überblick

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.

Einführung

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
  }
}

@bindsIst 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 { override fun get(): MainActivitySubcomponentBuilder { return MainActivitySubcomponentBuilder() } }


 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#createDas 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

Verstehen Sie, was die Android-Unterstützung von Dagger2 bewirkt
Was ist Cubby?
Was ist null? ]]
Was ist java
Was ist Schlüsselumhang?
Was ist Maven?
Was ist Jackson?
Was ist Selbst
Was ist Jenkins?
Was ist ArgumentMatcher?
Was ist IM-Jonglieren?
Was ist params
Was ist SLF4J?
Was ist Fassade? ??
Was ist Java <>?
Was ist Gradle?
Was ist POJO?
Was ist java
Was macht [Rails DB: Migrieren]?
Was ist centOS?
Was ist RubyGem?
Was ist before_action?
Was ist Docker?
Was ist Byte?
Was ist Tomcat?
Was ist Maven Assembly?
Was ist Docker-Compose?
Was ist vue cli
Was ist eine Schnittstelle?
Was ist Rubys Selbst?
Was ist harte Codierung?
Was ist ein Stream?
Was ist Rubys attr_accessor?
Was ist Java-Kapselung?
Was ist die Erlaubnis verweigert?
Was ist Instanzsteuerung?
Was ist ein Initialisierer?
Was ist Spring Tools 4?
Was ist ein Operator?
Was ist Objektorientierung?
Was ist Guavas @VisibleForTesting?
Was ist ein MVC-Modell?
Was ist eine Anmerkung?
Was ist Java-Technologie?
Was ist Java API-Java?
Was ist @ (Instanzvariable)?
Was ist Gradles Artefakt?
Was ist JPA-Prüfung?
[Java] Was ist flatMap?
Was ist ein Servlet?
Was ist Webentwicklung?
[Java] Was ist ArrayList?