Внедрение зависимостей с помощью Hilt (Views)

Основные понятия и реализация Jetpack Compose

Hilt – это библиотека внедрения зависимостей для Android, которая сокращает объем шаблонного кода, необходимого для внедрения зависимостей вручную. При ручном внедрении зависимостей вам нужно вручную создавать каждый класс и его зависимости, а также использовать контейнеры для повторного использования зависимостей и управления ими.

Hilt предоставляет стандартный способ использования DI в вашем приложении, предоставляя контейнеры для каждого класса Android в вашем проекте и автоматически управляя их жизненными циклами. Hilt основан на популярной библиотеке DI Dagger, что позволяет использовать преимущества Dagger, такие как правильность во время компиляции, производительность во время выполнения, масштабируемость и поддержка Android Studio. Подробнее о Hilt и Dagger…

В этом руководстве объясняются основные понятия Hilt и сгенерированных контейнеров. Также в нем показано, как настроить существующее приложение для использования Hilt.

Класс приложения Hilt

Все приложения, использующие Hilt, должны содержать класс Application с аннотацией @HiltAndroidApp.

@HiltAndroidApp запускает генерацию кода Hilt, включая базовый класс для вашего приложения, который служит контейнером зависимостей на уровне приложения.

Kotlin

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

Java

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

Этот сгенерированный компонент Hilt прикреплен к жизненному циклу объекта Application и предоставляет ему зависимости. Кроме того, это родительский компонент приложения, а значит, другие компоненты могут получать доступ к предоставляемым им зависимостям.

Внедрение зависимостей в классы Android

После того как вы настроите Hilt в классе Application и станет доступен компонент уровня приложения, Hilt сможет предоставлять зависимости другим классам Android, у которых есть аннотация @AndroidEntryPoint:

Kotlin

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

Java

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

В настоящее время Hilt поддерживает следующие классы Android:

  • Application (с помощью @HiltAndroidApp)
  • ViewModel (с помощью @HiltViewModel)
  • Activity
  • Fragment
  • View
  • Service
  • BroadcastReceiver

Если вы добавите аннотацию @AndroidEntryPoint в класс Android, то вам также потребуется добавить ее в зависимые классы Android. Например, если вы аннотируете фрагмент, то должны также аннотировать все действия, в которых он используется.

@AndroidEntryPoint генерирует отдельный компонент Hilt для каждого класса Android в проекте. Эти компоненты могут получать зависимости от своих родительских классов, как описано в разделе Иерархия компонентов.

Чтобы получить зависимости от компонента, используйте аннотацию @Inject для внедрения через поле:

Kotlin

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}

Java

@AndroidEntryPoint
public class ExampleActivity extends AppCompatActivity {

  @Inject
  AnalyticsAdapter analytics;
  ...
}

Классы, в которые Hilt внедряет зависимости, могут иметь другие базовые классы, которые также используют внедрение. Для абстрактных классов аннотация @AndroidEntryPoint не требуется.

Подробнее о том, в какой обратный вызов жизненного цикла внедряется класс Android, рассказывается в разделе Время жизни компонента.

Определите привязки Hilt

Чтобы выполнить внедрение через поле, Hilt нужно знать, как предоставить экземпляры необходимых зависимостей из соответствующего компонента. Привязка содержит информацию, необходимую для предоставления экземпляров типа в качестве зависимости.

Один из способов предоставить Hilt информацию о привязке – внедрение через конструктор. Используйте аннотацию @Inject в конструкторе класса, чтобы указать Hilt, как предоставлять экземпляры этого класса:

Kotlin

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

Java

public class AnalyticsAdapter {

  private final AnalyticsService service;

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

Параметры аннотированного конструктора класса являются зависимостями этого класса. В примере AnalyticsAdapter зависит от AnalyticsService. Поэтому Hilt также должен знать, как предоставлять экземпляры AnalyticsService.

Модули Hilt

Иногда тип нельзя внедрить через конструктор. Это может происходить по нескольким причинам. Например, вы не можете внедрить интерфейс через конструктор. Вы также не можете внедрить через конструктор тип, который вам не принадлежит, например класс из внешней библиотеки. В таких случаях вы можете предоставить Hilt информацию о привязке, используя модули Hilt.

Модуль Hilt – это класс, аннотированный с помощью @Module. Как и модуль Dagger, он сообщает Hilt, как предоставлять экземпляры определенных типов. В отличие от модулей Dagger, модули Hilt необходимо аннотировать с помощью @InstallIn, чтобы указать, в каком классе Android будет использоваться или устанавливаться каждый модуль.

Зависимости, которые вы предоставляете в модулях Hilt, доступны во всех сгенерированных компонентах, связанных с классом Android, в котором вы устанавливаете модуль Hilt.

Внедрение экземпляров интерфейса с помощью @Binds

Рассмотрим пример с AnalyticsService. Если AnalyticsService – это интерфейс, то вы не можете внедрить его через конструктор. Вместо этого предоставьте Hilt информацию о привязке, создав абстрактную функцию с аннотацией @Binds внутри модуля Hilt.

Аннотация @Binds сообщает Hilt, какую реализацию использовать, когда нужно предоставить экземпляр интерфейса.

Аннотированная функция предоставляет Hilt следующую информацию:

  • Тип возвращаемого значения функции сообщает Hilt, какой интерфейс предоставляет функция. экземпляры.
  • Параметр функции сообщает Hilt, какую реализацию предоставить.

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

Модуль Hilt AnalyticsModule аннотирован с помощью @InstallIn(ActivityComponent.class), потому что вы хотите, чтобы Hilt внедрил эту зависимость в ExampleActivity. Эта аннотация означает, что все зависимости в AnalyticsModule доступны во всех действиях приложения.

Внедрение экземпляров с помощью @Provides

Интерфейсы – не единственный случай, когда нельзя внедрить тип через конструктор. Внедрение через конструктор также невозможно, если вы не являетесь владельцем класса, поскольку он получен из внешней библиотеки (например, классы Retrofit, OkHttpClient или базы данных Room), или если экземпляры должны создаваться с помощью шаблона Builder.

Рассмотрим предыдущий пример. Если вы не являетесь владельцем класса AnalyticsService, вы можете указать Hilt, как предоставлять экземпляры этого типа, создав функцию внутри модуля Hilt и аннотировав ее с помощью @Provides.

Аннотированная функция предоставляет Hilt следующую информацию:

  • Тип возвращаемого значения функции сообщает Hilt, экземпляры какого типа предоставляет функция.
  • Параметры функции сообщают Hilt о зависимостях соответствующего типа.
  • Тело функции сообщает Hilt, как предоставить экземпляр соответствующего типа. Hilt выполняет тело функции каждый раз, когда ему нужно предоставить экземпляр этого типа.

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

Предоставление нескольких привязок для одного типа

Если вам нужно, чтобы Hilt предоставлял разные реализации одного типа в качестве зависимостей, вам необходимо предоставить Hilt несколько привязок. Вы можете определить несколько привязок для одного типа с помощью квалификаторов.

Квалификатор – это аннотация, которая используется для идентификации конкретной привязки для типа, когда для этого типа определено несколько привязок.

Рассмотрим пример. Если вам нужно перехватывать вызовы AnalyticsService, вы можете использовать объект OkHttpClient с перехватчиком. Для других сервисов может потребоваться другой способ перехвата вызовов. В этом случае вам нужно указать Hilt, как предоставить две разные реализации OkHttpClient.

Сначала определите квалификаторы, которые вы будете использовать для аннотирования методов @Binds или @Provides:

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

Затем Hilt нужно знать, как предоставить экземпляр типа, соответствующий каждому квалификатору. В этом случае можно использовать модуль Hilt с @Provides. Оба метода имеют один и тот же тип возвращаемого значения, но квалификаторы помечают их как две разные привязки:

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

Вы можете внедрить нужный тип, добавив к полю или параметру соответствующий квалификатор:

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

Рекомендуется, если вы добавляете квалификатор к типу, добавлять квалификаторы ко всем возможным способам предоставления этой зависимости. Если оставить базовую или общую реализацию без квалификатора, это может привести к ошибкам и внедрению неправильной зависимости.

Стандартные квалификаторы в Hilt

В Hilt есть несколько предопределенных квалификаторов. Например, если вам нужен класс Context из приложения или действия, Hilt предоставляет квалификаторы @ApplicationContext и @ActivityContext.

Предположим, что классу AnalyticsAdapter из примера нужен контекст действия. В следующем примере кода показано, как передать контекст действия в 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;
  }
}

Другие предопределенные привязки, доступные в Hilt, перечислены в разделе Привязки компонентов по умолчанию.

Сгенерированные компоненты для классов Android

Для каждого класса Android, в котором можно выполнить внедрение через поле, есть связанный компонент Hilt, на который можно сослаться в аннотации @InstallIn. Каждый компонент Hilt отвечает за внедрение своих привязок в соответствующий класс Android.

В предыдущих примерах показано использование ActivityComponent в модулях Hilt.

Hilt предоставляет следующие компоненты:

Компонент Hilt Инжектор для
SingletonComponent Application
ActivityRetainedComponent Н/Д
ViewModelComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent View с аннотацией @WithFragmentBindings
ServiceComponent Service

Срок службы компонентов

Hilt автоматически создает и удаляет экземпляры сгенерированных классов компонентов в соответствии с жизненным циклом соответствующих классов Android.

Сгенерированный компонент Создано Удалено
SingletonComponent Application#onCreate() Application уничтожено
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ViewModelComponent Создано: ViewModel ViewModel уничтожено
ActivityComponent Activity#onCreate() Activity#onDestroy()
FragmentComponent Fragment#onAttach() Fragment#onDestroy()
ViewComponent View#super() View уничтожено
ViewWithFragmentComponent View#super() View уничтожено
ServiceComponent Service#onCreate() Service#onDestroy()

Области действия компонентов

По умолчанию все привязки в Hilt не имеют области действия. Это означает, что каждый раз, когда приложение запрашивает привязку, Hilt создает новый экземпляр нужного типа.

В примере каждый раз, когда Hilt предоставляет AnalyticsAdapter в качестве зависимости другому типу или через внедрение через поле (как в ExampleActivity), Hilt предоставляет новый экземпляр AnalyticsAdapter.

Однако Hilt также позволяет привязать привязку к определенному компоненту. Hilt создает привязку с ограниченной областью действия только один раз для каждого экземпляра компонента, к которому привязана привязка, и все запросы для этой привязки используют один и тот же экземпляр.

В таблице ниже перечислены аннотации области действия для каждого сгенерированного компонента:

Класс Android Сгенерированный компонент Область действия
Application SingletonComponent @Singleton
Activity ActivityRetainedComponent @ActivityRetainedScoped
ViewModel ViewModelComponent @ViewModelScoped
Activity ActivityComponent @ActivityScoped
Fragment FragmentComponent @FragmentScoped
View ViewComponent @ViewScoped
View с аннотацией @WithFragmentBindings ViewWithFragmentComponent @ViewScoped
Service ServiceComponent @ServiceScoped

В примере, если вы ограничите область действия AnalyticsAdapter до ActivityComponent с помощью @ActivityScoped, Hilt будет предоставлять один и тот же экземпляр AnalyticsAdapter на протяжении всего жизненного цикла соответствующей операции:

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

Предположим, что у AnalyticsService есть внутреннее состояние, которое требует, чтобы один и тот же экземпляр использовался каждый раз не только в ExampleActivity, но и в любом месте приложения. В этом случае целесообразно ограничить область действия AnalyticsService до SingletonComponent. В результате каждый раз, когда компоненту нужно предоставить экземпляр AnalyticsService, он предоставляет один и тот же экземпляр.

В следующем примере показано, как ограничить привязку компонентом в модуле Hilt. Область действия привязки должна соответствовать области действия компонента, в котором она установлена. Поэтому в этом примере вы должны установить AnalyticsService в SingletonComponent вместо 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);
  }
}

Подробнее об областях действия компонентов Hilt…

Иерархия компонентов

Установка модуля в компонент позволяет получить доступ к его привязкам как к зависимости других привязок в этом компоненте или в любом дочернем компоненте ниже его в иерархии компонентов:

ViewWithFragmentComponent находится в FragmentComponent. FragmentComponent и ViewComponent находятся в ActivityComponent. ActivityComponent находится в ActivityRetainedComponent. ViewModelComponent находится в ActivityRetainedComponent. ActivityRetainedComponent и ServiceComponent находятся в SingletonComponent.
Рисунок 1. Иерархия компонентов, которые генерирует Hilt.

Привязки по умолчанию для компонентов

Каждый компонент Hilt поставляется с набором привязок по умолчанию, которые Hilt может внедрять в качестве зависимостей в ваши собственные пользовательские привязки. Обратите внимание, что эти привязки соответствуют общим типам действий и фрагментов, а не какому-либо конкретному подклассу. Это связано с тем, что Hilt использует одно определение компонента действия для внедрения всех действий. Для каждого действия используется отдельный экземпляр этого компонента.

Компонент Android Привязки по умолчанию
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

Привязка контекста приложения также доступна в @ApplicationContext. Пример:

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

Привязка контекста действия также доступна с помощью @ActivityContext. Пример:

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

Внедрение зависимостей в классы, не поддерживаемые Hilt

Hilt поддерживает самые распространенные классы Android. Однако вам может потребоваться выполнить внедрение через поле в классах, которые не поддерживаются Hilt.

В таких случаях вы можете создать точку входа с помощью аннотации @EntryPoint. Точка входа – это граница между кодом, управляемым Hilt, и кодом, который им не управляется. Это точка, в которой код впервые входит в граф объектов, управляемых Hilt. Точки входа позволяют Hilt использовать код, которым Hilt не управляет, для предоставления зависимостей в графе зависимостей.

Например, Hilt не поддерживает поставщиков контента напрямую. Если вы хотите, чтобы поставщик контента использовал Hilt для получения некоторых зависимостей, вам нужно определить интерфейс, аннотированный с помощью @EntryPoint для каждого нужного типа привязки, и включить квалификаторы. Затем добавьте @InstallIn, чтобы указать компонент, в который нужно установить точку входа, как показано ниже:

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

Чтобы получить доступ к точке входа, используйте подходящий статический метод из EntryPointAccessors. В качестве параметра следует использовать экземпляр компонента или объект @AndroidEntryPoint, который выступает в качестве держателя компонента. Убедитесь, что компонент, который вы передаете в качестве параметра, и статический метод EntryPointAccessors соответствуют классу Android в аннотации @InstallIn интерфейса @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();
  }
}

В этом примере для получения точки входа необходимо использовать ApplicationContext, поскольку точка входа установлена в SingletonComponent. Если бы нужная привязка находилась в ActivityComponent, вы бы использовали ActivityContext.

Hilt и Dagger

Hilt основана на библиотеке внедрения зависимостей Dagger и предоставляет стандартный способ включения Dagger в приложение для Android.

По сравнению с Dagger, Hilt имеет следующие цели:

  • Чтобы упростить инфраструктуру, связанную с Dagger, для приложений Android.
  • Создать стандартный набор компонентов и областей действия, чтобы упростить настройку, чтение и обмен кодом между приложениями.
  • Чтобы упростить предоставление разных привязок для разных типов сборки, например тестирования, отладки или выпуска.

Поскольку операционная система Android создает экземпляры многих собственных классов фреймворка, использование Dagger в приложении Android требует написания значительного количества шаблонного кода. Hilt сокращает объем шаблонного кода, который используется при работе с Dagger в приложении для Android. Hilt автоматически генерирует и предоставляет следующее:

  • Компоненты для интеграции классов фреймворка Android с Dagger, которые в противном случае вам пришлось бы создавать вручную.
  • Аннотации области действия для использования с компонентами, которые Hilt генерирует автоматически.
  • Предопределенные привязки для представления классов Android, таких как Application или Activity.
  • Стандартные модификаторы, представляющие @ApplicationContext и @ActivityContext.

Код Dagger и Hilt может сосуществовать в одной базе кода. Однако в большинстве случаев лучше использовать Hilt для управления всеми вашими использованиями Dagger на Android. Чтобы перенести проект, в котором используется Dagger, в Hilt, ознакомьтесь с руководством по переносу.