Wstrzykiwanie zależności za pomocą Hilt

Hilt to biblioteka do wstrzykiwania zależności na Androidzie, która redukuje powtórzenia ręcznego wstrzykiwania zależności w projekcie. Stosowanie zależności ręcznej wstrzyknięcie kodu wymaga utworzenia wszystkich klas i ich zależności, a także używanie kontenerów do ponownego i zarządzać zależnościami.

Hilt udostępnia standardowy sposób korzystania z modułu DI w aplikacji, kontenery dla wszystkich klas Androida w projekcie oraz zarządzanie ich cyklami życia automatycznie. Hilt opiera się na popularnej bibliotece DI szkoła, aby skorzystać z Poprawność podczas kompilacji, wydajność środowiska wykonawczego, skalowalność i Android Studio pomocy które zapewnia Dagger. Więcej informacji znajdziesz w artykule na temat Krzyżyk.

W tym przewodniku wyjaśniamy podstawowe pojęcia dotyczące Hilt i jego generowanych kontenerów. it zawiera również demonstrację tego, jak uruchomić istniejącą aplikację do użycia Hilt.

Dodawanie zależności

Najpierw dodaj wtyczkę hilt-android-gradle-plugin do katalogu głównego projektu Plik build.gradle:

Odlotowe

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
}

Następnie zastosuj wtyczkę Gradle i dodaj te zależności w pliku Plik app/build.gradle:

Odlotowe

...
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 korzysta z funkcji Java 8. Aby włączyć obsługę języka Java 8 w: Twojego projektu, do pliku app/build.gradle dodaj:

Odlotowe

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

Klasa aplikacji Hilt

Wszystkie aplikacje korzystające z Hilt muszą zawierać parametr Zajęcia Application z adnotacjami @HiltAndroidApp

@HiltAndroidApp wyzwala generowanie kodu Hilt, w tym klasę bazową dla polecenia w której Twoja aplikacja pełni funkcję kontenera zależności na poziomie aplikacji.

Kotlin

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

Java

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

Ten wygenerowany komponent Hilt został dołączony do komponentu Application cyklu życia i określa ich zależności. Dodatkowo jest to tag nadrzędny, jest komponent aplikacji, co oznacza, że inne komponenty mają dostęp do jakie daje.

Wstrzykiwanie zależności do klas Androida

Po skonfigurowaniu Hilt w klasie Application i na poziomie aplikacji komponent, Hilt może podać zależności innym klasom Androida które zawierają adnotację @AndroidEntryPoint:

Kotlin

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

Java

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

Hilt obsługuje obecnie te klasy Androida:

  • Application (za pomocą: @HiltAndroidApp)
  • ViewModel (za pomocą: @HiltViewModel)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

Jeśli dodajesz adnotacje do zajęć Androida za pomocą funkcji @AndroidEntryPoint, musisz też dodawać adnotacje do klas Androida, które są od niego zależne. Na przykład jeśli dodasz adnotację musisz też dodać adnotacje do wszystkich działań, w których go używasz fragment.

@AndroidEntryPoint generuje pojedynczy komponent Hilt dla każdego Androida w ramach projektu. Te komponenty mogą otrzymywać zależności odpowiednich klas nadrzędnych zgodnie z opisem w sekcji Komponent hierarchii.

Aby uzyskać zależności od komponentu, użyj adnotacji @Inject wstrzykiwanie przez pola:

Kotlin

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}

Java

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @Inject
  AnalyticsAdapter analytics;
  ...
}

Klasy wstrzykiwane przez Hilt mogą mieć inne klasy podstawowe, które również używają wstrzykiwania. Te zajęcia nie wymagają adnotacji @AndroidEntryPoint, jeśli są abstrakcyjne.

Aby dowiedzieć się więcej o wywołaniu zwrotnym w cyklu życia, do którego wstrzykiwana jest klasa Androida, przeczytaj artykuł Okresy życia komponentów.

Zdefiniuj powiązania Hilt

Aby wykonać wstrzykiwanie przez pole, Hilt musi wiedzieć, jak udostępnić wystąpienia niezbędne zależności od odpowiedniego komponentu. Powiązanie zawiera informacje niezbędne do sporządzenia wystąpień określonego typu jako zależności.

Jednym ze sposobów na przekazanie informacji o powiązaniu do Hilt jest wstrzykiwanie przez konstruktora. Używaj adnotacji @Inject w konstruktorze klasy informującej Hilt, jak wykonać należy podać instancje tej klasy:

Kotlin

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

Java

public class AnalyticsAdapter {

  private final AnalyticsService service;

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

Parametry konstruktora klasy z adnotacjami to zależności tej klasy. W tym przykładzie AnalyticsAdapter ma AnalyticsService jako zależności. Dlatego też Hilt musi wiedzieć, jak udostępniać AnalyticsService

Moduły Hilt

Czasami typ nie może być wstrzykiwany przez konstruktor. Może się tak dziać w przypadku wielu . Na przykład nie można wstawić interfejsu przez konstruktor. Dodatkowo nie możesz wprowadzić przez konstruktor typu typu, który nie należy do Ciebie, na przykład klasy z z biblioteką zewnętrzną. W takich przypadkach możesz podać usłudze Hilt informacje wiążące za pomocą modułów Hilt.

Moduł Hilt to klasa oznaczona adnotacją @Module. Jak sztylet , informuje Hilt, jak udostępniać wystąpienia określonych typów. W przeciwieństwie do modułów daggera musisz dodać adnotacje do modułów Hilt (@InstallIn), aby poinformować Hilt, który z nich w której poszczególne moduły będą używane lub zainstalowane.

Zależności podane w modułach Hilt są dostępne we wszystkich wygenerowanych powiązane z klasą Androida, w której instalujesz Moduł Hilt.

Wstrzykiwanie instancji interfejsu za pomocą @Binds

Przyjrzyjmy się przykładowi AnalyticsService. Jeśli AnalyticsService to interfejs, nie będzie można go wstrzyknąć przez konstruktor. Zamiast tego podaj Hiltowi powiązanie przez utworzenie funkcji abstrakcyjnej z adnotacją @Binds w elemencie Moduł Hilt.

Adnotacja @Binds informuje Hilt, której implementacji użyć, gdy musi udostępnia instancję interfejsu.

Funkcja z adnotacjami przekazuje Hilt te informacje:

  • Typ zwracania funkcji informuje Hilt o tym, jaki interfejs udostępnia funkcja .
  • Parametr funkcji informuje Hilt, którą implementację wyświetlić.

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

Moduł Hilt (AnalyticsModule) ma adnotację @InstallIn(ActivityComponent.class), bo chcesz, by Hilt wstrzykiwał to zależność w: ExampleActivity. Ta adnotacja oznacza, że wszystkie zależności w AnalyticsModule są dostępne we wszystkich działaniach w aplikacji.

Wstrzykiwanie instancji za pomocą @Provides

Interfejsy nie są jedynym przypadkiem, w którym nie można wstawić typu przez konstruktor. Wstrzyknięcie konstruktora jest też niemożliwe, jeśli nie jesteś właścicielem klasy, ponieważ pochodzące z biblioteki zewnętrznej (klasy takie jak Retrofit, OkHttpClient, lub baz danych sal) lub jeśli instancje muszą należy utworzyć za pomocą konstruktora .

Przeanalizuj poprzedni przykład. Jeśli nie jesteś bezpośrednim właścicielem domeny AnalyticsService możesz poinformować Hilt, jak udostępnić instancje tego typu, tworząc w module Hilt, dodając do niego adnotacje @Provides.

Funkcja z adnotacjami przekazuje do Hilt te informacje:

  • Typ zwracany funkcji informuje Hilt o typie zwracanych przez funkcję
  • Parametry funkcji informują Hilt o zależności odpowiedniego typu.
  • Treść funkcji informuje Hilt o tym, jak podać wystąpienie odpowiednich typu. Hilt wykonuje treść funkcji za każdym razem, gdy musi dostarczyć wystąpienia tego typu.

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

Podaj wiele powiązań tego samego typu

Gdy chcesz, aby usługa Hilt dostarczała różne implementacje tego samego jako zależności, musisz podać Hilt z wieloma powiązaniami. Dostępne opcje zdefiniować wiele powiązań tego samego typu za pomocą kwalifikatorów.

Kwalifikator to adnotacja służąca do identyfikowania konkretnego wiązania dla jeśli ten typ ma zdefiniowanych wiele powiązań.

Przeanalizujmy przykład. Jeśli chcesz przechwytywać połączenia z numerem AnalyticsService, może użyć obiektu OkHttpClient z przechwytującego. Dla: możesz przechwytywać połączenia w inny sposób. Pod tym kątem musisz poinformować Hilt, jak udostępnić 2 różne implementacje OkHttpClient

Najpierw zdefiniuj kwalifikatory, których będziesz używać do dodawania adnotacji do właściwości @Binds lub @Provides metody:

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

Następnie Hilt musi wiedzieć, jak udostępnić wystąpienie typu odpowiadającego z każdym kwalifikatorem. W takim przypadku możesz użyć modułu Hilt z narzędziem @Provides. Obie metody mają ten sam typ zwrotu, ale kwalifikatory oznaczają je jako dwie różne powiązania:

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();
  }
}

Możesz wstrzyknąć konkretny typ, którego potrzebujesz, dodając adnotacje do pola lub z odpowiednim kwalifikatorem:

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

Jeśli dodasz kwalifikator do typu, dodaj je do wszystkich wartości atrybutu do uzyskania tej zależności. Opuszczanie bazy lub wspólnej implementacja bez kwalifikatora jest podatna na błędy i może spowodować wystąpienie błędu wstrzykiwanie niewłaściwej zależności.

Wstępnie zdefiniowane kwalifikatory w Hilt

Hilt udostępnia kilka wstępnie zdefiniowanych kwalifikatorów. Na przykład, ponieważ możesz potrzebować Context z aplikacji lub aktywności, Hilt udostępnia Kwalifikacje: @ApplicationContext i @ActivityContext.

Załóżmy, że klasa AnalyticsAdapter z przykładu wymaga kontekstu aktywność. Ten kod ilustruje, jak podać działanie kontekst do 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;
  }
}

Informacje o innych wstępnie zdefiniowanych powiązaniach dostępnych w Hilt znajdziesz w sekcji Ustawienie domyślne komponentu

Wygenerowane komponenty klas Androida

W przypadku każdej klasy Androida, w której można wstrzykiwać pola, powiązanego komponentu Hilt, do którego możesz się odwołać w adnotacji @InstallIn. Każdy komponent Hilt jest odpowiedzialny za wstrzykiwanie swoich wiązań z odpowiednią klasą Androida.

Poprzednie przykłady ilustrowały użycie funkcji ActivityComponent w Hilt modułów.

Hilt udostępnia te komponenty:

Komponent z trzonkiem Wtryskiwacz do
SingletonComponent Application
ActivityRetainedComponent Nie dotyczy
ViewModelComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent View ma adnotację z: @WithFragmentBindings
ServiceComponent Service

Czasy eksploatacji komponentów

Hilt automatycznie tworzy i niszczy instancje wygenerowanych klas komponentów zgodnie z cyklem życia odpowiednich klas Androida.

Wygenerowany komponent Utworzono o Zniszczono o
SingletonComponent Application#onCreate() Zniszczono: Application
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ViewModelComponent Utworzono ViewModel Zniszczono: ViewModel
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() Zniszczono: View
ViewWithFragmentComponent View#super() Zniszczono: View
ServiceComponent Service#onCreate() Service#onDestroy()

Zakresy komponentów

Domyślnie wszystkie powiązania w Hilt są nieograniczone. Oznacza to, że za każdym razem, gdy Twój aplikacja żąda powiązania, Hilt tworzy nową instancję potrzebnego typu.

W tym przykładzie Hilt udostępnia funkcję AnalyticsAdapter jako zależność innego typu lub przez wstrzykiwanie przez pola (jak w ExampleActivity), Hilt zapewnia nową instancję instancji AnalyticsAdapter.

Hilt umożliwia jednak również ograniczenie powiązania do konkretnego komponentu. Rzep tworzy powiązanie zakresu tylko raz na wystąpienie komponentu, które powiązanie ma zakres ograniczony do zakresu i wszystkie żądania tego powiązania korzystają z tej samej instancji.

Tabela poniżej zawiera adnotacje zakresu dla każdego wygenerowanego komponentu:

Zajęcia dotyczące Androida Wygenerowany komponent Zakres
Application SingletonComponent @Singleton
Activity ActivityRetainedComponent @ActivityRetainedScoped
ViewModel ViewModelComponent @ViewModelScoped
Activity ActivityComponent @ActivityScoped
Fragment FragmentComponent @FragmentScoped
View ViewComponent @ViewScoped
View ma adnotację z: @WithFragmentBindings ViewWithFragmentComponent @ViewScoped
Service ServiceComponent @ServiceScoped

Jeśli w tym przykładzie ustawisz zakres AnalyticsAdapter na ActivityComponent za pomocą interfejsu @ActivityScoped Hilt udostępnia tę samą instancję AnalyticsAdapter w ciągu całego cyklu aktywności:

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

Załóżmy, że AnalyticsService ma stan wewnętrzny, który wymaga tego samego do użycia za każdym razem – nie tylko w regionie ExampleActivity, ale w dowolnym miejscu aplikację. W tym przypadku odpowiednie jest zastosowanie zakresu AnalyticsService do SingletonComponent Dzięki temu za każdym razem, gdy komponent musi podany instancję AnalyticsService, co każdorazowo obecnie się znajdujesz.

Przykład poniżej pokazuje, jak określić zakres powiązania do komponentu w Moduł Hilt. Zakres powiązania musi pasować do zakresu komponentu, w którym się znajduje jest już zainstalowany, więc w tym przykładzie musisz zainstalować AnalyticsService SingletonComponent zamiast 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);
  }
}

Więcej informacji o zakresach komponentów Hilt znajdziesz w artykułach na temat określania zakresu w Androidzie i Hilt.

Hierarchia komponentów

Zainstalowanie modułu w komponencie umożliwia dostęp do jego powiązań zależność innych powiązań w tym komponencie lub w dowolnym komponencie podrzędnym poniżej w hierarchii komponentów:

ViewWithFragmentKomponent znajduje się w sekcji FragmentKomponent. Składnik fragmentu
    i WidokKomponentu znajdują się w sekcji Aktywność. Komponent Aktywność jest w
    Wskaźnik aktywności. Komponent ViewModelKomponent znajduje się w
    Wskaźnik aktywności. Parametr aktywności i usługaSkładnik
    są w komponencie Singleton.
Rysunek 1. Hierarchia komponentów Hilt i generowanie konwersji.

Domyślne powiązania komponentu

Każdy komponent Hilt zawiera zestaw domyślnych wiązań, które Hilt może wstrzykiwać jako we własnych powiązaniach niestandardowych. Zwróć uwagę, że te powiązania odpowiadają do ogólnej aktywności i typów fragmentów, a nie do poszczególnych podklas. Dzieje się tak, ponieważ Hilt używa definicji pojedynczego komponentu aktywności do wstrzykiwania wszystkich aktywności. Każda aktywność ma inną instancję tego komponentu.

Komponent Androida Powiązania domyślne
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

Powiązanie kontekstu aplikacji jest też dostępne za pomocą funkcji @ApplicationContext. Na przykład:

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

Powiązanie kontekstu działania jest też dostępne za pomocą funkcji @ActivityContext. Dla: przykład:

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

Wstrzykiwanie zależności w klasach nieobsługiwanych przez Hilt

Hilt obsługuje większość popularnych klas aplikacji na Androida. Możesz jednak muszą wykonywać wstrzykiwanie pól w klasach, których Hilt nie obsługuje.

W takich przypadkach możesz utworzyć punkt wejścia za pomocą funkcji @EntryPoint adnotacja. Punkt wejścia to granica między kodem zarządzanym przez Hilt a z drugiej – nie. Jest to punkt, w którym kod po raz pierwszy zostaje umieszczony na wykresie obiektami zarządzanymi przez Hilta. Dzięki punktom wejścia Hilt może używać kodu takiego, jaki robi Hilt nie mogą określać zależności w obrębie grafu zależności.

Na przykład Hilt nie obsługuje bezpośrednio treści dostawców usług. Jeśli chcesz, aby treści aby użyć Hilt do uzyskania pewnych zależności, musisz zdefiniować interfejs które są oznaczone adnotacjami @EntryPoint w przypadku każdego wybranego typu powiązania, uwzględnij kwalifikatory. Następnie dodaj @InstallIn, aby określić komponent, w którym ma być zainstaluj punkt wejścia w następujący sposób:

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();
  }
  ...
}

Aby uzyskać dostęp do punktu wejścia, użyj odpowiedniej metody statycznej z EntryPointAccessors Parametr powinien być instancją komponentu lub obiekt @AndroidEntryPoint, który jest właścicielem komponentu. Upewnij się, że komponent przekazywany jako parametr, a element statyczny EntryPointAccessors dopasowują się do klasy Androida w adnotacji @InstallIn w Interfejs @EntryPoint:

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();
  }
}

W tym przykładzie do pobrania wpisu musisz użyć polecenia ApplicationContext ponieważ punkt wejścia jest instalowany w SingletonComponent. Jeśli które chcesz odzyskać, znajdowały się w ActivityComponent, zamiast tego użyj funkcji ActivityContext.

Krzyżyk i krzyżyk

Hilt jest zamontowany na kieszonce sztylet biblioteka do wstrzykiwania zależności, zapewniająca standardowy sposób wdrażania narzędzia Dagger. w aplikację na Androida.

W przypadku Daggera cele Hilt są następujące:

  • Aby uprościć infrastrukturę aplikacji na Androida związaną z daggerem.
  • Aby utworzyć standardowy zestaw komponentów i zakresów w celu uproszczenia konfiguracji, czytelności i udostępnianie kodu między aplikacjami.
  • Aby ułatwić udostępnianie różnych powiązań do różnych typów kompilacji, takich jak testowanie, debugowanie czy wdrażanie.

Ponieważ system operacyjny Android tworzy instancję wielu własnych platform. zajęć, używanie Daggera w aplikacji na Androida wymaga napisania istotnej czy być stały. Hilt redukuje powtarzalny kod używając Daggera w aplikacji na Androida. Hilt automatycznie generuje zapewnia:

  • Komponenty do integrowania zajęć na platformie Android z Daggerem w przeciwnym razie musiałaby tworzyć ręcznie.
  • Adnotacje dotyczące zakresu – do wykorzystania z komponentami generowanymi przez Hilta automatycznie.
  • Wstępnie zdefiniowane powiązania reprezentujące klasy Androida, takie jak Application lub Activity
  • Wstępnie zdefiniowane kwalifikatory reprezentujące wartości @ApplicationContext i @ActivityContext

Kod sztyletu i kod Hilt mogą współistnieć w tej samej bazie kodu. Jednak w większości przypadków najlepiej jest używać Hilt do zarządzania całym korzystaniem z daggera na Androidzie. Migracja projektu korzystającego ze sztyletu do Hilt – zapoznaj się z sekcją Migracja i Migrowaniu aplikacja Dagger do Hilt

Dodatkowe materiały

Aby dowiedzieć się więcej o Hilt, zapoznaj się z dodatkowymi materiałami poniżej.

Próbki

Ćwiczenia z programowania

Blogi