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. Ręczne wstrzyknięcie zależności wymaga ręcznego tworzenia każdej klasy i jej zależności oraz używania kontenerów do ponownego używania i zarządzania zależnościami.

Hilt udostępnia standardowy sposób wykorzystania DI w aplikacji, kontenery dla każdej klasy Androida w projekcie i zarządzanie ich cyklami życia automatycznie. Hilt jest oparty na popularnej bibliotece DI Dagger, aby korzystać z prawidłowego działania w czasie kompilacji, wydajności w czasie wykonywania, skalowalności i obsługi Android Studio. Więcej informacji znajdziesz w artykule Hilt and Dagger.

W tym przewodniku wyjaśniamy podstawowe pojęcia dotyczące usługi Hilt i wygenerowanych przez nią kontenerów. Znajdziesz w nim też demonstrację uruchamiania istniejącej aplikacji za pomocą Hilt.

Dodawanie zależności

Najpierw dodaj wtyczkę hilt-android-gradle-plugin do pliku build.gradle w katalogu głównym projektu:

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

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

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

android {
  ...
}

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

// Allow references to generated code
kapt {
  correctErrorTypes true
}
plugins {
  id("kotlin-kapt")
  id("com.google.dagger.hilt.android")
}

android {
  ...
}

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

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

Hilt korzysta z funkcji języka Java 8. Aby włączyć Java 8 w projekcie, dodaj do pliku app/build.gradle następujący wiersz:

GroovyKotlin
android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}
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 powoduje wygenerowanie kodu przez Hilta, w tym klasy podstawowej aplikacji, która służy jako kontener zależności na poziomie aplikacji.

KotlinJava
@HiltAndroidApp
class ExampleApplication : Application() { ... }
@HiltAndroidApp
public class ExampleApplication extends Application { ... }

Ten wygenerowany komponent Hilt jest dołączony do cyklu życia obiektu Application i zawiera jego 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

Gdy Hilt zostanie skonfigurowany w klasie Application i będzie dostępny komponent na poziomie aplikacji, Hilt może udostępniać zależności innym klasom Androida, które mają adnotację @AndroidEntryPoint:

KotlinJava
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() { ... }
@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. Jeśli np. dodasz adnotację do fragmentu, musisz też dodać adnotacje do wszystkich aktywności, w których używasz tego fragmentu.

@AndroidEntryPoint generuje osobny komponent Hilt dla każdej klasy Androida w projekcie. Te komponenty mogą otrzymywać zależności z odpowiednich klas nadrzędnych zgodnie z opisem w hierarchii komponentów.

Aby uzyskać zależności od komponentu, użyj adnotacji @Inject do wykonania wstrzyknięcia pola:

KotlinJava
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}
@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 potrzebują 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.

Definiowanie powiązań Hilt

Aby wykonać wstrzyknięcie pola, Hilt musi wiedzieć, jak udostępnić wystąpienia niezbędnych zależności z odpowiedniego komponentu. Binding zawiera informacje potrzebne do udostępnienia instancji typu jako zależności.

Jednym ze sposobów przekazywania informacji do Hilta jest wstrzyknięcie konstruktora. Użyj adnotację @Inject w konstruktorze klasy informującej Hilt, jak wykonać należy podać instancje tej klasy:

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

  private final AnalyticsService service;

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

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

Moduły Hilt

Czasami nie można wstrzyknąć typu za pomocą konstruktora. Może się tak zdarzyć z kilku powodów. 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. Podobnie jak moduł Dagger informuje Hilt, jak udostępniać instancje określonych typów. W przeciwieństwie do modułów Dagger musisz opatrzyć moduły Hilt adnotacjami @InstallIn, aby poinformować Hilt, w której klasie Androida ma być używany lub instalowany każdy moduł.

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

Rozważ przykład 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ępnić 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ć.
KotlinJava
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
}
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 nie jest też możliwe, jeśli nie jesteś właścicielem klasy, ponieważ pochodzi ona z biblioteki zewnętrznej (klasy takie jak Retrofit, OkHttpClient lub bazy danych Room) lub jeśli instancje muszą być tworzone za pomocą schematu budowania.

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 podają Hilt zależności odpowiedniego typu.
  • Ciało funkcji określa, jak Hilt ma podać wystąpienie odpowiedniego typu. Hilt wykonuje treść funkcji za każdym razem, gdy musi dostarczyć wystąpienia tego typu.
KotlinJava
@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)
  }
}
@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);
  }
}

Podawanie wielu 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. Za pomocą kwalifikatorów możesz zdefiniować wiele powiązań tego samego typu.

Kwalifikator to adnotacja, która służy do identyfikowania określonego powiązania typu, gdy dany typ ma zdefiniowane liczne powiązania.

Przeanalizujmy przykład. Jeśli chcesz przechwytywać połączenia z numerem AnalyticsService, może użyć obiektu OkHttpClient z przechwytującego. W przypadku innych usług może być konieczne przechwytywanie połączeń w inny sposób. W takim przypadku musisz podać Hiltowi informacje o tym, jak udostępnić 2 różne implementacje funkcji OkHttpClient.

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

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

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
private @interface AuthInterceptorOkHttpClient {}

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

Następnie Hilt musi wiedzieć, jak podać instancję typu, która odpowiada każdemu ograniczeniu. W takim przypadku możesz użyć modułu Hilt z funkcją @Provides. Obie metody mają ten sam typ zwracanej wartości, ale kwalifikatory oznaczają je jako 2 różne typy powiązań:

KotlinJava
@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()
  }
}
@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ąć określony typ, którego potrzebujesz, oznaczając pole lub parametr odpowiednim ogranicznikiem:

KotlinJava
// 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
}
// 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 skutkować wstrzykiwanie niewłaściwej zależności.

Wstępnie zdefiniowane kwalifikatory w Hilt

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

Załóżmy, że klasa AnalyticsAdapter z przykładu potrzebuje kontekstu czynności. Ten kod ilustruje, jak podać działanie kontekst do AnalyticsAdapter:

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

  private final Context context;
  private final AnalyticsService service;

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

Inne wstępnie zdefiniowane powiązania dostępne w Hilt znajdziesz w sekcji Domyślne powiązania komponentów.

Wygenerowane komponenty dla klas Android

W przypadku każdej klasy Androida, w której można wykonywać wstrzyknięcie pola, istnieje powiązany komponent Hilt, do którego można się odwoływać w adnotacji @InstallIn. Każdy komponent Hilt odpowiada za wstrzyknięcie swoich powiązań do odpowiedniej klasy Androida.

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

Hilt udostępnia te komponenty:

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

Czas życia 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() Application zniszczone
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ViewModelComponent Utworzono ViewModel ViewModel zniszczone
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() View zniszczone
ViewWithFragmentComponent View#super() View zniszczone
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 aplikacja żąda powiązania, Hilt tworzy nową instancję wymaganego 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. Hilt tworzy ograniczone wiązanie tylko raz na instancję komponentu, do którego jest ono ograniczone, a wszystkie żądania tego wią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 z adnotacją @WithFragmentBindings ViewWithFragmentComponent @ViewScoped
Service ServiceComponent @ServiceScoped

W tym przykładzie, jeśli zawęzisz zakres AnalyticsAdapter do ActivityComponent za pomocą @ActivityScoped, Hilt udostępnia ten sam element AnalyticsAdapter przez cały czas trwania odpowiedniej czynności:

KotlinJava
@ActivityScoped
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }
@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, aby za każdym razem używano tego samego wystąpienia, nie tylko w ExampleActivity, ale w dowolnym miejscu w aplikacji. W tym przypadku odpowiednie jest ograniczenie 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 działania powiązania musi być zgodny z zakresem komponentu, w którym jest zainstalowany. W tym przykładzie musisz zainstalować AnalyticsServiceSingletonComponent zamiast ActivityComponent:

KotlinJava
// 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)
  }
}
// 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 zakresie działania komponentów Hilt znajdziesz w artykule Zapisywanie zakresu działania 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ści jest podelementem komponentu ActivityRetainedComponent. Element ViewModelKomponent znajduje się w
    Wskaźnik aktywności. Parametr aktywności i Servicemont
    są w komponencie Singleton.
Rysunek 1. Hierarchia komponentów Hilt i generowanie konwersji.

Powiązania domyślne komponentów

Każdy komponent Hilt jest dostarczany z zestawem domyślnych powiązań, które Hilt może wstrzyknąć jako zależności do własnych niestandardowych powiązań. Pamiętaj, że te powiązania odpowiadają ogólnym typom aktywności i fragmentów, a nie poszczególnym podklasom. Dzieje się tak, ponieważ Hilt używa jednej definicji komponentu aktywności do wstrzykiwania wszystkich aktywności. Każda aktywność ma inne wystąpienie tego komponentu.

Komponent Android Domyślne powiązania
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

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

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

// The Application binding is available without qualifiers.
class AnalyticsServiceImpl @Inject constructor(
  application: Application
) : AnalyticsService { ... }
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;
  }
}

Wiązanie kontekstu aktywności jest też dostępne za pomocą @ActivityContext. Dla: przykład:

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

// The Activity binding is available without qualifiers.
class AnalyticsAdapter @Inject constructor(
  activity: FragmentActivity
) { ... }
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ść typowych klas Androida. Może jednak być konieczne wykonanie wstrzyknięcia pola w klasach, których Hilt nie obsługuje.

W takich przypadkach możesz utworzyć punkt wejścia za pomocą adnotacji @EntryPoint. 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 wchodzi do grafu obiektów zarządzanych przez Hilt. Punkty wejścia umożliwiają Hiltowi korzystanie z kodu, który nie jest w stanie zapewnić zależności w ramach grafu zależności.

Na przykład Hilt nie obsługuje bezpośrednio dostawców treści. 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 chcesz zainstalować punkt wejścia:

KotlinJava
class ExampleContentProvider : ContentProvider() {

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

  ...
}
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ć wystąpieniem komponentu lub obiektem @AndroidEntryPoint, który pełni funkcję uchwytu komponentu. Upewnij się, że komponent przekazywany jako parametr i statyczna metoda EntryPointAccessors pasują do klasy Android w adnotacji @InstallIn w interfejsie @EntryPoint:

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

Hilt and Dagger

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, który ułatwia konfigurację, czytelność i udostępnianie kodu między aplikacjami.
  • Aby ułatwić tworzenie różnych powiązań dla różnych typów kompilacji, takich jak testowanie, debugowanie czy wersja.

System operacyjny Android tworzy wiele własnych klas frameworka, więc korzystanie z Daggera w aplikacji na Androida wymaga napisania dużej ilości kodu stałego. Hilt zmniejsza ilość kodu stałego używanego do korzystania z Daggera w aplikacji na Androida. Hilt automatycznie generuje i udostępnia te funkcje:

  • 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 @ApplicationContext@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. Aby przenieść projekt korzystający z Daggera do Hilta, zapoznaj się z przewodnikiem i z sesją Codelab poświęconą migracji aplikacji Dagger do Hilta.

Dodatkowe materiały

Więcej informacji o Hilt znajdziesz w tych dodatkowych materiałach.

Próbki

Dowiedz się, jak wdrożyć konfiguracje zarządzane, które mogą być zmienione przez inne aplikacje na tym samym urządzeniu.

Funkcje Androida dla firm zapewniają organizacjom ujednolicona platforma mobilności Androida – łączy urządzenia, aplikacje i zarządzaniem. Aplikacje na Androida są zgodne z funkcjami biznesowymi Androida domyślnie. Istnieją jednak dodatkowe funkcje,

Dowiedz się, jak zadbać o sprawne działanie aplikacji w środowisku firmowym, stosując sprawdzone metody.

Ćwiczenia z programowania

Blogi