Abhängigkeitsinjektion mit Hilt

Hilt ist eine Abhängigkeitsinjektionsbibliothek für Android, die den Standardtext der manuellen Abhängigkeitsinjektion in Ihrem Projekt. Manuelle Abhängigkeit Injektion erfordert, dass Sie jede Klasse und ihre Abhängigkeiten manuell zu erstellen um Abhängigkeiten zu verwalten.

Hilt bietet eine standardmäßige Möglichkeit, DI in Ihrer Anwendung zu verwenden, indem es Container für jede Android-Klasse in Ihrem Projekt und die Verwaltung ihrer Lebenszyklen automatisch. Hilt basiert auf der beliebten DI-Bibliothek Dagger, um von der Korrektheit der Kompilierungszeit, Laufzeitleistung, Skalierbarkeit und Android Studio von Dagger. Weitere Informationen finden Sie unter Hilt- und Dolch.

In diesem Leitfaden werden die grundlegenden Konzepte von Hilt und die zugehörigen Container erläutert. Es enthält auch eine Demonstration für das Bootstrapping einer vorhandenen App für die Verwendung von Hilt.

Abhängigkeiten hinzufügen

Fügen Sie zuerst das Plug-in hilt-android-gradle-plugin dem Stammverzeichnis Ihres Projekts hinzu build.gradle-Datei:

Cool

plugins {
  ...
  id 'com.google.dagger.hilt.android' version '2.44' apply false
}

Kotlin

plugins {
  ...
  id("com.google.dagger.hilt.android") version "2.44" apply false
}

Wenden Sie dann das Gradle-Plug-in an und fügen Sie diese Abhängigkeiten app/build.gradle-Datei:

Cool

...
plugins {
  id 'kotlin-kapt'
  id 'com.google.dagger.hilt.android'
}

android {
  ...
}

dependencies {
  implementation "com.google.dagger:hilt-android:2.44"
  kapt "com.google.dagger:hilt-compiler:2.44"
}

// Allow references to generated code
kapt {
  correctErrorTypes true
}

Kotlin

plugins {
  id("kotlin-kapt")
  id("com.google.dagger.hilt.android")
}

android {
  ...
}

dependencies {
  implementation("com.google.dagger:hilt-android:2.44")
  kapt("com.google.dagger:hilt-android-compiler:2.44")
}

// Allow references to generated code
kapt {
  correctErrorTypes = true
}

Hilt verwendet Java 8-Funktionen. Um Java 8 in Ihrem Projekt fügen Sie der Datei app/build.gradle Folgendes hinzu:

Cool

android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

Kotlin

android {
  ...
  compileOptions {
    sourceCompatibility = JavaVersion.VERSION_1_8
    targetCompatibility = JavaVersion.VERSION_1_8
  }
}

Hilt-Anwendungsklasse

Alle Apps, die Hilt verwenden, müssen ein Application-Klasse, die mit annotiert ist @HiltAndroidApp.

@HiltAndroidApp löst die Codegenerierung von Hilt aus, einschließlich einer Basisklasse für Ihrer Anwendung, die als Abhängigkeitscontainer auf Anwendungsebene dient.

Kotlin

@HiltAndroidApp
class ExampleApplication : Application() { ... }

Java

@HiltAndroidApp
public class ExampleApplication extends Application { ... }

Diese generierte Hilt-Komponente wird an das Objekt Application und stellt Abhängigkeiten bereit. Außerdem ist es das übergeordnete Element, Komponente der App. Das bedeutet, dass andere Komponenten auf die Abhängigkeiten, die sie bietet.

Abhängigkeiten in Android-Klassen einfügen

Sobald Hilt in Ihrer Application-Klasse und einer Anwendungsebene Komponente verfügbar ist, kann Hilt Abhängigkeiten für andere Android-Klassen bereitstellen. mit der Anmerkung @AndroidEntryPoint:

Kotlin

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() { ... }

Java

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity { ... }

Hilt unterstützt derzeit die folgenden Android-Klassen:

  • Application (mit @HiltAndroidApp)
  • ViewModel (mit @HiltViewModel)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

Wenn Sie eine Android-Klasse mit @AndroidEntryPoint annotieren, müssen Sie auch Android-Klassen annotieren, die davon abhängig sind. Wenn Sie zum Beispiel ein Fragmentieren, müssen Sie auch alle Aktivitäten annotieren, bei denen Sie dieses Fragment.

<ph type="x-smartling-placeholder">

@AndroidEntryPoint generiert eine eigene Hilt-Komponente für jedes Android-Gerät in Ihrem Projekt beginnen. Diese Komponenten können Abhängigkeiten von ihrem entsprechenden übergeordneten Klassen, wie unter Komponente Hierarchie.

Wenn Sie Abhängigkeiten von einer Komponente abrufen möchten, verwenden Sie die Anmerkung @Inject, um Field Injection:

Kotlin

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}

Java

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @Inject
  AnalyticsAdapter analytics;
  ...
}

Klassen, die von Hilt injiziert werden, können andere Basisklassen haben, die ebenfalls Injektion verwenden. Diese Klassen benötigen die Annotation @AndroidEntryPoint nicht, abstrakt sind.

Weitere Informationen dazu, in welchen Lebenszyklus-Callback eine Android-Klasse eingeschleust wird, Siehe Lebensdauer von Komponenten

Hilt-Bindungen definieren

Um Feldeinschleusungen durchführen zu können, muss Hilt wissen, wie Instanzen der die erforderlichen Abhängigkeiten von der entsprechenden Komponente. Eine binding enthält die Informationen, die erforderlich sind, um Instanzen eines Typs als Abhängigkeit bereitzustellen.

Eine Möglichkeit, Hilt-Bindungsinformationen bereitzustellen, ist die Konstruktoreinschleusung. Verwenden Sie der Annotation @Inject für den Konstruktor einer Klasse, um Hilt mitzuteilen, Instanzen dieser Klasse bereitstellen:

Kotlin

class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }

Java

public class AnalyticsAdapter {

  private final AnalyticsService service;

  @Inject
  AnalyticsAdapter(AnalyticsService service) {
    this.service = service;
  }
  ...
}

Die Parameter eines annotierten Konstruktors einer Klasse sind die Abhängigkeiten für diesen Kurs. In diesem Beispiel hat AnalyticsAdapter AnalyticsService als Abhängigkeit. Daher muss Hilt wissen, wie Instanzen von AnalyticsService

<ph type="x-smartling-placeholder">

Hilt-Module

Manchmal kann ein Typ nicht in den Konstruktor eingefügt werden. Dies kann bei mehreren Gründe. Sie können beispielsweise keine Schnittstelle mit dem Konstruktor injizieren. Außerdem kann keinen Typ, der Ihnen nicht gehört, durch den Konstruktor injizieren, z. B. eine Klasse aus einem externe Bibliothek. In diesen Fällen können Sie Hilt Informationen zur Bindung mithilfe von Hilt-Modulen.

Ein Hilt-Modul ist eine Klasse, die mit @Module annotiert ist. Wie ein Dolch Modul informiert Hilt darüber, wie Instanzen bestimmter Typen bereitgestellt werden. Im Gegensatz zu Dagger-Modulen Sie müssen Hilt-Module mit @InstallIn annotieren, um Hilt mitzuteilen, Klasse, in der jedes Modul verwendet oder installiert wird.

Abhängigkeiten, die Sie in Hilt-Modulen angeben, sind in allen generierten Komponenten, die mit der Android-Klasse verknüpft sind, in der Sie die Hilt-Modul.

Schnittstelleninstanzen mit @Binds einschleusen

Sehen Sie sich das Beispiel AnalyticsService an. Wenn AnalyticsService eine Schnittstelle ist, können Sie ihn nicht per Konstruktor einschleusen. Stellen Sie stattdessen Hilt die Bindung durch Erstellen einer abstrakten Funktion, die mit @Binds in einem Hilt-Modul.

Die Annotation @Binds teilt Hilt mit, welche Implementierung wann verwendet werden soll. eine Instanz einer Schnittstelle bereitstellen.

Die annotierte Funktion stellt Hilt die folgenden Informationen zur Verfügung:

  • Der Rückgabetyp der Funktion teilt Hilt mit, welche Schnittstelle die Funktion bietet Instanzen von.
  • Der Funktionsparameter teilt Hilt mit, welche Implementierung bereitgestellt werden soll.

Kotlin

interface AnalyticsService {
  fun analyticsMethods()
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
class AnalyticsServiceImpl @Inject constructor(
  ...
) : AnalyticsService { ... }

@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {

  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}

Java

public interface AnalyticsService {
  void analyticsMethods();
}

// Constructor-injected, because Hilt needs to know how to
// provide instances of AnalyticsServiceImpl, too.
public class AnalyticsServiceImpl implements AnalyticsService {
  ...
  @Inject
  AnalyticsServiceImpl(...) {
    ...
  }
}

@Module
@InstallIn(ActivityComponent.class)
public abstract class AnalyticsModule {

  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}

Das Hilt-Modul AnalyticsModule ist mit @InstallIn(ActivityComponent.class), weil Hilt das in Ihre Abhängigkeit in ExampleActivity. Diese Anmerkung bedeutet, dass alle Abhängigkeiten in AnalyticsModule sind in allen Aktivitäten der Anwendung verfügbar.

Instanzen mit @Provides einfügen

Schnittstellen sind nicht der einzige Fall, bei dem Sie einen Typ nicht konstruktor einschleusen können. Das Einfügen von Konstruktoren ist auch nicht möglich, wenn Sie nicht der Eigentümer der Klasse sind, da sie aus einer externen Bibliothek stammen (Klassen wie Rückblick OkHttpClient, oder Raumdatenbanken) oder ob Instanzen mit dem Builder erstellt werden, Muster.

Betrachten Sie das vorherige Beispiel. Wenn Sie nicht der direkte Inhaber von AnalyticsService sind können Sie Hilt anweisen, wie Instanzen dieses Typs bereitgestellt werden. Dazu erstellen Sie eine in einem Hilt-Modul enthalten ist, und versehen Sie diese Funktion mit @Provides.

Die annotierte Funktion stellt Hilt die folgenden Informationen bereit:

  • Der Rückgabetyp der Funktion teilt Hilt mit, welchen Typ die Funktion bereitstellt. von.
  • Die Funktionsparameter informieren Hilt über die Abhängigkeiten des entsprechenden Typs.
  • Der Funktionstext teilt Hilt mit, wie eine Instanz der entsprechenden Typ. Hilt führt den Funktionstext jedes Mal aus, wenn ein Instanz dieses Typs.

Kotlin

@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    // Potential dependencies of this type
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService::class.java)
  }
}

Java

@Module
@InstallIn(ActivityComponent.class)
public class AnalyticsModule {

  @Provides
  public static AnalyticsService provideAnalyticsService(
    // Potential dependencies of this type
  ) {
      return new Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService.class);
  }
}

Mehrere Bindungen für denselben Typ angeben

In Fällen, in denen Hilt verschiedene Implementierungen derselben als Abhängigkeiten eingeben, müssen Sie Hilt mehrere Bindungen bereitstellen. Sie können Mithilfe von Qualifier können Sie mehrere Bindungen für denselben Typ definieren.

Ein Qualifier ist eine Annotation, mit der Sie eine bestimmte Bindung für eine wenn für diesen Typ mehrere Bindungen definiert sind.

Betrachten Sie das Beispiel. Wenn Sie Aufrufe an AnalyticsService abfangen müssen, kann ein OkHttpClient-Objekt mit einem Interceptor. Für andere Dienste verwenden, müssen Sie Aufrufe eventuell anders abfangen. Dabei müssen Sie Hilt mitteilen, wie zwei verschiedene Implementierungen OkHttpClient

Definieren Sie zuerst die Qualifier, mit denen Sie die @Binds- oder @Provides-Methoden:

Kotlin

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptorOkHttpClient

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient

Java

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
private @interface AuthInterceptorOkHttpClient {}

@Qualifier
@Retention(RetentionPolicy.RUNTIME)
private @interface OtherInterceptorOkHttpClient {}

Dann muss Hilt wissen, wie eine Instanz des Typs mit jedem Qualifier. In diesem Fall könnten Sie ein Hilt-Modul mit @Provides verwenden. Beide Methoden haben denselben Rückgabetyp, werden aber von den Kennzeichnern als zwei gekennzeichnet verschiedenen Bindungen:

Kotlin

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

  @AuthInterceptorOkHttpClient
  @Provides
  fun provideAuthInterceptorOkHttpClient(
    authInterceptor: AuthInterceptor
  ): OkHttpClient {
      return OkHttpClient.Builder()
               .addInterceptor(authInterceptor)
               .build()
  }

  @OtherInterceptorOkHttpClient
  @Provides
  fun provideOtherInterceptorOkHttpClient(
    otherInterceptor: OtherInterceptor
  ): OkHttpClient {
      return OkHttpClient.Builder()
               .addInterceptor(otherInterceptor)
               .build()
  }
}

Java

@Module
@InstallIn(ActivityComponent.class)
public class NetworkModule {

  @AuthInterceptorOkHttpClient
  @Provides
  public static OkHttpClient provideAuthInterceptorOkHttpClient(
    AuthInterceptor authInterceptor
  ) {
      return new OkHttpClient.Builder()
                   .addInterceptor(authInterceptor)
                   .build();
  }

  @OtherInterceptorOkHttpClient
  @Provides
  public static OkHttpClient provideOtherInterceptorOkHttpClient(
    OtherInterceptor otherInterceptor
  ) {
      return new OkHttpClient.Builder()
                   .addInterceptor(otherInterceptor)
                   .build();
  }
}

Sie können den spezifischen Typ, den Sie benötigen, einschleusen, indem Sie das Feld oder durch den entsprechenden Qualifier:

Kotlin

// As a dependency of another class.
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    @AuthInterceptorOkHttpClient okHttpClient: OkHttpClient
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .client(okHttpClient)
               .build()
               .create(AnalyticsService::class.java)
  }
}

// As a dependency of a constructor-injected class.
class ExampleServiceImpl @Inject constructor(
  @AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient
) : ...

// At field injection.
@AndroidEntryPoint
class ExampleActivity: AppCompatActivity() {

  @AuthInterceptorOkHttpClient
  @Inject lateinit var okHttpClient: OkHttpClient
}

Java

// As a dependency of another class.
@Module
@InstallIn(ActivityComponent.class)
public class AnalyticsModule {

  @Provides
  public static AnalyticsService provideAnalyticsService(
    @AuthInterceptorOkHttpClient OkHttpClient okHttpClient
  ) {
      return new Retrofit.Builder()
                  .baseUrl("https://example.com")
                  .client(okHttpClient)
                  .build()
                  .create(AnalyticsService.class);
  }
}

// As a dependency of a constructor-injected class.
public class ExampleServiceImpl ... {

  private final OkHttpClient okHttpClient;

  @Inject
  ExampleServiceImpl(@AuthInterceptorOkHttpClient OkHttpClient okHttpClient) {
    this.okHttpClient = okHttpClient;
  }
}

// At field injection.
@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @AuthInterceptorOkHttpClient
  @Inject
  OkHttpClient okHttpClient;
  ...
}

Als Best Practice sollten Sie, wenn Sie einem Typ einen Qualifier hinzufügen, allen wie Sie diese Abhängigkeit bereitstellen können. Die Basis- oder Gewohnheitsform Implementierung ohne Qualifier ist fehleranfällig und kann Hilt zur Folge haben. die falsche Abhängigkeit einschleusen.

Vordefinierte Kennzeichner in Hilt

Hilt bietet einige vordefinierte Qualifier. Zum Beispiel, weil Sie möglicherweise das Context aus der Anwendung oder der Aktivität erstellt, stellt Hilt Die Qualifizierer @ApplicationContext und @ActivityContext.

Angenommen, die Klasse AnalyticsAdapter aus dem Beispiel benötigt den Kontext eines der Aktivität. Der folgende Code zeigt, wie die Aktivität bereitgestellt wird: Kontext zu AnalyticsAdapter:

Kotlin

class AnalyticsAdapter @Inject constructor(
    @ActivityContext private val context: Context,
    private val service: AnalyticsService
) { ... }

Java

public class AnalyticsAdapter {

  private final Context context;
  private final AnalyticsService service;

  @Inject
  AnalyticsAdapter(
    @ActivityContext Context context,
    AnalyticsService service
  ) {
    this.context = context;
    this.service = service;
  }
}

Informationen zu weiteren vordefinierten Bindungen, die in Hilt verfügbar sind, finden Sie unter Komponentenstandard bindings.

Generierte Komponenten für Android-Klassen

Für jeden Android-Kurs, in dem Sie Field Injections durchführen können, gibt es eine zugehörige Hilt-Komponente, auf die Sie in der Anmerkung @InstallIn verweisen können. Jede Hilt-Komponente ist für das Einfügen ihrer Bindungen in die der entsprechenden Android-Klasse.

In den vorherigen Beispielen wurde die Verwendung von ActivityComponent in Hilt demonstriert. Module.

Hilt bietet die folgenden Komponenten:

Hilt-Komponente Injektor für
SingletonComponent Application
ActivityRetainedComponent
ViewModelComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent View mit @WithFragmentBindings annotiert
ServiceComponent Service

Lebensdauer von Komponenten

Hilt erstellt automatisch Instanzen generierter Komponentenklassen und zerstört sie nach dem Lebenszyklus der entsprechenden Android-Klassen.

Generierte Komponente Erstellt um Gelöscht um
SingletonComponent Application#onCreate() Application gelöscht
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ViewModelComponent ViewModel erstellt ViewModel gelöscht
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() View gelöscht
ViewWithFragmentComponent View#super() View gelöscht
ServiceComponent Service#onCreate() Service#onDestroy()

Komponentenbereiche

Standardmäßig sind alle Bindungen in Hilt ohne Geltungsbereich. Das bedeutet, dass jedes Mal, wenn Ihre App die Bindung anfordert, erstellt Hilt eine neue Instanz des benötigten Typs.

In diesem Beispiel stellt Hilt jedes Mal, wenn Hilt AnalyticsAdapter als Abhängigkeit von eines anderen Typs oder über Field Injection (wie in ExampleActivity) bietet Hilt eine neue Instanz von AnalyticsAdapter.

Mit Hilt kann eine Bindung jedoch auch auf eine bestimmte Komponente beschränkt werden. Griff erstellt nur einmal pro Instanz der Komponente, die vom Bindung ist beschränkt auf und alle Anfragen für diese Bindung teilen sich dieselbe Instanz.

In der folgenden Tabelle sind die Annotationen zum Umfang für jede generierte Komponente aufgeführt:

Android-Kurs Generierte Komponente Aufgabenstellung
Application SingletonComponent @Singleton
Activity ActivityRetainedComponent @ActivityRetainedScoped
ViewModel ViewModelComponent @ViewModelScoped
Activity ActivityComponent @ActivityScoped
Fragment FragmentComponent @FragmentScoped
View ViewComponent @ViewScoped
View mit @WithFragmentBindings annotiert ViewWithFragmentComponent @ViewScoped
Service ServiceComponent @ServiceScoped

Wenn Sie im Beispiel den Bereich AnalyticsAdapter auf den ActivityComponent Mit @ActivityScoped stellt Hilt dieselbe Instanz von AnalyticsAdapter bereit. während der gesamten Lebensdauer der entsprechenden Aktivität:

Kotlin

@ActivityScoped
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }

Java

@ActivityScoped
public class AnalyticsAdapter {

  private final AnalyticsService service;

  @Inject
  AnalyticsAdapter(AnalyticsService service) {
    this.service = service;
  }
  ...
}

Angenommen, AnalyticsService hat einen internen Status, der denselben jedes Mal zu verwenden – nicht nur in ExampleActivity, sondern überall in in der App. In diesem Fall ist es sinnvoll, AnalyticsService auf den SingletonComponent Das hat zur Folge, dass jedes Mal, wenn die Komponente eine Instanz von AnalyticsService angeben, wird dieselbe Instanz bereitgestellt, .

Das folgende Beispiel zeigt, wie Sie eine Bindung auf eine Komponente in einer Hilt-Modul. Der Geltungsbereich einer Bindung muss mit dem Bereich der Komponente übereinstimmen, in der sie sich befindet installiert, also müssen Sie AnalyticsService in diesem Beispiel in SingletonComponent statt ActivityComponent:

Kotlin

// If AnalyticsService is an interface.
@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {

  @Singleton
  @Binds
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl
  ): AnalyticsService
}

// If you don't own AnalyticsService.
@Module
@InstallIn(SingletonComponent::class)
object AnalyticsModule {

  @Singleton
  @Provides
  fun provideAnalyticsService(): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService::class.java)
  }
}

Java

// If AnalyticsService is an interface.
@Module
@InstallIn(SingletonComponent.class)
public abstract class AnalyticsModule {

  @Singleton
  @Binds
  public abstract AnalyticsService bindAnalyticsService(
    AnalyticsServiceImpl analyticsServiceImpl
  );
}

// If you don't own AnalyticsService.
@Module
@InstallIn(SingletonComponent.class)
public class AnalyticsModule {

  @Singleton
  @Provides
  public static AnalyticsService provideAnalyticsService() {
      return new Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService.class);
  }
}

Weitere Informationen zu den Bereichen von Hilt-Komponenten finden Sie unter Umfang in Android und Hilt.

Komponentenhierarchie

Wenn Sie ein Modul in einer Komponente installieren, kann auf dessen Bindungen als Abhängigkeit von anderen Bindungen in dieser Komponente oder in einer untergeordneten Komponente in der Komponentenhierarchie:

<ph type="x-smartling-placeholder">
</ph> ViewWithFragmentComponent befindet sich unter &quot;FragmentComponent&quot;. FragmentComponent
    und ViewComponent
unter ActivityComponent befinden. ActivityComponent befindet sich unter
    ActivityRetainedComponent. ViewModelComponent befindet sich unter
    ActivityRetainedComponent. ActivityRetainedComponent und ServiceComponent
    befinden sich unter SingletonComponent.
Abbildung 1: Hierarchie der in Hilt verwendeten Komponenten generiert.

Standardbindungen für Komponenten

Jede Hilt-Komponente verfügt über eine Reihe von Standardbindungen, die von Hilt als in Ihre eigenen benutzerdefinierten Bindungen. Beachten Sie, dass diese Bindungen auf die allgemeinen Aktivitäts- und Fragmenttypen und nicht auf eine bestimmte Unterklasse. Das liegt daran, dass Hilt eine einzelne Aktivitätskomponente verwendet, um alle Aktivitäten. Jede Aktivität hat eine andere Instanz dieser Komponente.

Android-Komponente Standardbindungen
SingletonComponent Application
ActivityRetainedComponent Application
ViewModelComponent SavedStateHandle
ActivityComponent Application, Activity
FragmentComponent Application, Activity, Fragment
ViewComponent Application, Activity, View
ViewWithFragmentComponent Application, Activity, Fragment, View
ServiceComponent Application, Service

Die Kontextbindung der Anwendung ist auch mit @ApplicationContext verfügbar. Beispiel:

Kotlin

class AnalyticsServiceImpl @Inject constructor(
  @ApplicationContext context: Context
) : AnalyticsService { ... }

// The Application binding is available without qualifiers.
class AnalyticsServiceImpl @Inject constructor(
  application: Application
) : AnalyticsService { ... }

Java

public class AnalyticsServiceImpl implements AnalyticsService {

  private final Context context;

  @Inject
  AnalyticsAdapter(@ApplicationContext Context context) {
    this.context = context;
  }
}

// The Application binding is available without qualifiers.
public class AnalyticsServiceImpl implements AnalyticsService {

  private final Application application;

  @Inject
  AnalyticsAdapter(Application application) {
    this.application = application;
  }
}

Die Aktivitätskontextbindung ist auch mit @ActivityContext verfügbar. Für Beispiel:

Kotlin

class AnalyticsAdapter @Inject constructor(
  @ActivityContext context: Context
) { ... }

// The Activity binding is available without qualifiers.
class AnalyticsAdapter @Inject constructor(
  activity: FragmentActivity
) { ... }

Java

public class AnalyticsAdapter {

  private final Context context;

  @Inject
  AnalyticsAdapter(@ActivityContext Context context) {
    this.context = context;
  }
}

// The Activity binding is available without qualifiers.
public class AnalyticsAdapter {

  private final FragmentActivity activity;

  @Inject
  AnalyticsAdapter(FragmentActivity activity) {
    this.activity = activity;
  }
}

Abhängigkeiten in Klassen einfügen, die von Hilt nicht unterstützt werden

Hilt unterstützt die gängigsten Android-Klassen. Sie können jedoch in Klassen, die von Hilt nicht unterstützt werden, Field Injection ausführen müssen.

In diesen Fällen können Sie einen Einstiegspunkt mit der @EntryPoint . Ein Einstiegspunkt ist die Grenze zwischen Code, der von Hilt verwaltet wird. und Code, der nicht so ist. Dies ist der Punkt, an dem Code zum ersten Mal in die Grafik Objekte, die von Hilt verwaltet werden. Einstiegspunkte ermöglichen es Hilt, Code zu nutzen, den Hilt auch tut Abhängigkeiten innerhalb des Abhängigkeitsdiagramms bereitzustellen.

Hilt unterstützt beispielsweise Inhalte nicht direkt Anbieter. Wenn Sie einen Inhalt damit Sie mit Hilt Abhängigkeiten abrufen können, müssen Sie eine Schnittstelle definieren das für jeden Bindungstyp, den Sie verwenden möchten, mit @EntryPoint annotiert ist. enthalten Kennzeichner. Fügen Sie dann @InstallIn hinzu, um die Komponente anzugeben, in der So installieren Sie den Zugangspunkt:

Kotlin

class ExampleContentProvider : ContentProvider() {

  @EntryPoint
  @InstallIn(SingletonComponent::class)
  interface ExampleContentProviderEntryPoint {
    fun analyticsService(): AnalyticsService
  }

  ...
}

Java

public class ExampleContentProvider extends ContentProvider {

  @EntryPoint
  @InstallIn(SingletonComponent.class)
  interface ExampleContentProviderEntryPoint {
    public AnalyticsService analyticsService();
  }
  ...
}

Um auf einen Einstiegspunkt zuzugreifen, verwenden Sie die entsprechende statische Methode von EntryPointAccessors Der Parameter sollte entweder die Komponenteninstanz oder Das @AndroidEntryPoint-Objekt, das als Komponentenhalter fungiert Achten Sie darauf, dass die Komponente, die Sie als Parameter übergeben, und das statische EntryPointAccessors-Element beide mit der Android-Klasse in der @InstallIn-Annotation der @EntryPoint-Schnittstelle:

Kotlin

class ExampleContentProvider: ContentProvider() {
    ...

  override fun query(...): Cursor {
    val appContext = context?.applicationContext ?: throw IllegalStateException()
    val hiltEntryPoint =
      EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint::class.java)

    val analyticsService = hiltEntryPoint.analyticsService()
    ...
  }
}

Java

public class ExampleContentProvider extends ContentProvider {

  @Override
  public Cursor query(...) {
    Context appContext = getContext().getApplicationContext();
    ExampleContentProviderEntryPoint hiltEntryPoint =
      EntryPointAccessors.fromApplication(appContext, ExampleContentProviderEntryPoint.class);
    AnalyticsService analyticsService = hiltEntryPoint.analyticsService();
  }
}

In diesem Beispiel müssen Sie ApplicationContext verwenden, um den Eintrag abzurufen da der Einstiegspunkt in SingletonComponent installiert ist. Wenn die Bindung in der ActivityComponent befinden, würden Sie verwenden Sie stattdessen ActivityContext.

Griff und Dolch

Der Hilt baut auf dem Dogger auf. Bibliothek für Abhängigkeitsinjektionen, die eine Standardmethode zur Integration von Dagger bietet in eine Android-App übertragen.

In Bezug auf Dagger verfolgt Hilt folgende Ziele:

  • Vereinfachung der Dagger-bezogenen Infrastruktur für Android-Apps
  • Zum Erstellen eines Standardsatzes von Komponenten und Bereichen, um Einrichtung, Lesbarkeit, und Codeaustausch zwischen Apps.
  • Um eine einfache Möglichkeit zu bieten, verschiedene Bindungen für verschiedene Build-Typen bereitzustellen, wie „Testen“, „Debuggen“ oder „Release“.

Da das Android-Betriebssystem viele seiner eigenen Frameworks instanziiert können Sie bei der Verwendung von Dagger in einer Android-App aus Textbausteinen. Hilt reduziert den Boilerplate-Code, der bei mit Dagger in einer Android-App. Hilt generiert automatisch bietet Folgendes:

  • Komponenten für die Integration von Android-Framework-Klassen in Dagger die sonst von Hand erstellt werden müssten.
  • Bereichsanmerkungen zur Verwendung mit den von Hilt generierten Komponenten automatisch.
  • Vordefinierte Bindungen zur Darstellung von Android-Klassen wie Application oder Activity.
  • Vordefinierte Qualifizierer zur Darstellung von @ApplicationContext und @ActivityContext.

Dagger- und Hilt-Code können in derselben Codebasis nebeneinander bestehen. In den meisten Fällen verwenden Sie am besten Hilt, um Ihre gesamte Nutzung von Dagger auf Android-Geräten zu verwalten. So migrieren Sie Ihr Konto: einem Projekt, bei dem Dagger zu Hilt verwendet wird, sehen Sie sich die Migration und in der Migrationsanleitung Ihre Dagger-App in Hilt Codelab aus.

Weitere Informationen

Weitere Informationen zu Hilt finden Sie in den folgenden zusätzlichen Ressourcen.

Produktproben

Codelabs

Blogs