Hilt — это библиотека внедрения зависимостей для Android, которая уменьшает объем рутинной работы по ручному внедрению зависимостей в вашем проекте. Ручное внедрение зависимостей требует от вас создания каждого класса и его зависимостей вручную, а также использования контейнеров для повторного использования и управления зависимостями.
Hilt предоставляет стандартный способ использования внедрения зависимостей (DI) в вашем приложении, предоставляя контейнеры для каждого класса Android в вашем проекте и автоматически управляя их жизненным циклом. Hilt построен на основе популярной библиотеки DI Dagger, что позволяет использовать преимущества корректности на этапе компиляции, производительности во время выполнения, масштабируемости и поддержки Android Studio , которые предоставляет Dagger. Для получения дополнительной информации см. Hilt и Dagger .
В этом руководстве объясняются основные концепции Hilt и создаваемых им контейнеров. Также приводится демонстрация того, как инициализировать существующее приложение для использования Hilt.
Добавление зависимостей
Сначала добавьте плагин hilt-android-gradle-plugin в корневой файл build.gradle вашего проекта:
Классный
plugins { ... id 'com.google.dagger.hilt.android' version '2.57.1' apply false }
Котлин
plugins { ... id("com.google.dagger.hilt.android") version "2.57.1" apply false }
Затем примените плагин Gradle и добавьте следующие зависимости в файл app/build.gradle :
Классный
... plugins { id 'com.google.devtools.ksp' id 'com.google.dagger.hilt.android' } android { ... } dependencies { implementation "com.google.dagger:hilt-android:2.57.1" ksp "com.google.dagger:hilt-compiler:2.57.1" }
Котлин
plugins { id("com.google.devtools.ksp") id("com.google.dagger.hilt.android") } android { ... } dependencies { implementation("com.google.dagger:hilt-android:2.57.1") ksp("com.google.dagger:hilt-android-compiler:2.57.1") }
Hilt использует возможности Java 8. Чтобы включить Java 8 в вашем проекте, добавьте следующее в файл app/build.gradle :
Классный
android { ... compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } }
Котлин
android { ... compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } }
класс приложений Hilt
Все приложения, использующие Hilt, должны содержать класс Application , аннотированный с помощью @HiltAndroidApp .
Аннотация @HiltAndroidApp запускает генерацию кода Hilt, включая базовый класс для вашего приложения, который служит контейнером зависимостей на уровне приложения.
Котлин
@HiltAndroidApp class ExampleApplication : Application() { ... }
Java
@HiltAndroidApp public class ExampleApplication extends Application { ... }
Сгенерированный компонент Hilt подключается к жизненному циклу объекта Application и предоставляет ему зависимости. Кроме того, он является родительским компонентом приложения, что означает, что другие компоненты могут получить доступ к предоставляемым им зависимостям.
Внедрение зависимостей в классы Android
После того как Hilt будет настроен в вашем классе Application и станет доступен компонент уровня приложения, Hilt сможет предоставлять зависимости другим классам Android, имеющим аннотацию @AndroidEntryPoint :
Котлин
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { ... }
Java
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { ... }
В настоящее время Hilt поддерживает следующие классы Android:
-
Application(с использованием@HiltAndroidApp) -
ViewModel(с использованием@HiltViewModel) -
Activity -
Fragment -
View -
Service -
BroadcastReceiver
Если вы аннотируете класс Android с помощью @AndroidEntryPoint , то вы также должны аннотировать классы Android, которые от него зависят. Например, если вы аннотируете фрагмент, то вы также должны аннотировать все активности, где используется этот фрагмент.
@AndroidEntryPoint генерирует отдельный компонент Hilt для каждого класса Android в вашем проекте. Эти компоненты могут получать зависимости от своих родительских классов, как описано в разделе «Иерархия компонентов» .
Для получения зависимостей от компонента используйте аннотацию @Inject для внедрения полей:
Котлин
@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, как предоставлять экземпляры этого класса:
Котлин
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 , чтобы указать Hilt, в каком классе Android будет использоваться или устанавливаться каждый модуль.
Зависимости, которые вы указываете в модулях Hilt, доступны во всех сгенерированных компонентах, связанных с классом Android, в который вы устанавливаете модуль Hilt.
Внедряйте экземпляры интерфейса с помощью аннотации @Binds
Рассмотрим пример AnalyticsService . Если AnalyticsService является интерфейсом, то его нельзя внедрить через конструктор. Вместо этого предоставьте Hilt информацию о привязке, создав абстрактную функцию, аннотированную @Binds , внутри модуля Hilt.
Аннотация @Binds указывает Hilt, какую реализацию использовать, когда необходимо предоставить экземпляр интерфейса.
Аннотированная функция предоставляет Хилту следующую информацию:
- Тип возвращаемого значения функции указывает Hilt, экземпляры какого интерфейса предоставляет эта функция.
- Параметр функции указывает Hilt, какую реализацию следует предоставить.
Котлин
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 выполняет тело функции каждый раз, когда ему необходимо предоставить экземпляр этого типа.
Котлин
@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 :
Котлин
@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 . Оба метода имеют одинаковый тип возвращаемого значения, но квалификаторы указывают на то, что это две разные привязки:
Котлин
@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(); } }
Вы можете указать необходимый тип, добавив к полю или параметру соответствующий квалификатор:
Котлин
// 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
Hilt предоставляет несколько предопределенных квалификаторов. Например, поскольку вам может потребоваться класс Context как из приложения, так и из активности, Hilt предоставляет квалификаторы @ApplicationContext и @ActivityContext .
Предположим, что классу AnalyticsAdapter из примера необходим контекст активности. Следующий код демонстрирует, как передать контекст активности классу AnalyticsAdapter :
Котлин
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 на протяжении всего жизненного цикла соответствующей активности:
Котлин
@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 :
Котлин
// 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, см. раздел «Области видимости в Android и 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 . Например:
Котлин
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 . Например:
Котлин
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 , чтобы указать компонент, в который следует установить точку входа, следующим образом:
Котлин
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 :
Котлин
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 , предоставляя стандартный способ интеграции Dagger в Android-приложения.
Что касается Даггера, то цели Хилта заключаются в следующем:
- Для упрощения инфраструктуры, связанной с Dagger, для приложений Android.
- Цель – создать стандартный набор компонентов и областей видимости для упрощения настройки, повышения читаемости и совместного использования кода между приложениями.
- Предоставить простой способ настройки различных привязок для разных типов сборки, таких как тестирование, отладка или релиз.
Поскольку операционная система Android создает экземпляры многих собственных классов фреймворка, использование Dagger в приложении Android требует написания значительного количества шаблонного кода. Hilt сокращает количество шаблонного кода, необходимого для использования Dagger в приложении Android. Hilt автоматически генерирует и предоставляет следующее:
- Компоненты для интеграции классов фреймворка Android с Dagger, которые в противном случае пришлось бы создавать вручную.
- Аннотации области видимости , используемые с компонентами, которые Hilt генерирует автоматически.
- Предопределенные привязки для представления классов Android, таких как
ApplicationилиActivity. - Предопределенные квалификаторы для представления
@ApplicationContextи@ActivityContext.
Код Dagger и Hilt может сосуществовать в одной кодовой базе. Однако в большинстве случаев лучше использовать Hilt для управления всем использованием Dagger на Android. Чтобы перенести проект, использующий Dagger, на Hilt, см. руководство по миграции и практическое руководство по миграции вашего приложения Dagger на Hilt .
Дополнительные ресурсы
Чтобы узнать больше о компании Hilt, ознакомьтесь со следующими дополнительными материалами.
Образцы
Кодлабс
Блоги
- Внедрение зависимостей в Android с помощью Hilt
- Определение области видимости в Android и Hilt
- Добавление компонентов в иерархию Hilt
- Перенос приложения Google I/O на платформу Hilt.