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.56.2' apply false }
Котлин
plugins { ... id("com.google.dagger.hilt.android") version "2.56.2" 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.56.2" ksp "com.google.dagger:hilt-compiler:2.56.2" }
Котлин
plugins { id("com.google.devtools.ksp") id("com.google.dagger.hilt.android") } android { ... } dependencies { implementation("com.google.dagger:hilt-android:2.56.2") ksp("com.google.dagger:hilt-android-compiler:2.56.2") }
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, должны содержать класс Application
, аннотированный @HiltAndroidApp
.
@HiltAndroidApp
запускает генерацию кода Hilt, включая базовый класс для вашего приложения, который служит контейнером зависимостей на уровне приложения.
Котлин
@HiltAndroidApp class ExampleApplication : Application() { ... }
Ява
@HiltAndroidApp public class ExampleApplication extends Application { ... }
Этот сгенерированный компонент Hilt прикрепляется к жизненному циклу объекта Application
и предоставляет ему зависимости. Кроме того, он является родительским компонентом приложения, что означает, что другие компоненты могут получить доступ к предоставляемым им зависимостям.
Внедрение зависимостей в классы Android
После настройки Hilt в классе вашего Application
и доступности компонента уровня приложения Hilt может предоставлять зависимости другим классам Android, имеющим аннотацию @AndroidEntryPoint
:
Котлин
@AndroidEntryPoint class ExampleActivity : AppCompatActivity() { ... }
Ява
@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 ... }
Ява
@AndroidEntryPoint public class ExampleActivity extends AppCompatActivity { @Inject AnalyticsAdapter analytics; ... }
Классы, внедряемые Hilt, могут иметь другие базовые классы, также использующие внедрение. Таким классам не требуется аннотация @AndroidEntryPoint
, если они абстрактные.
Дополнительную информацию о том, в какой обратный вызов жизненного цикла внедряется класс Android, см. в разделе Время жизни компонентов .
Определить крепления рукояти
Для внедрения полей Hilt необходимо знать, как предоставить экземпляры необходимых зависимостей из соответствующего компонента. Привязка содержит информацию, необходимую для предоставления экземпляров типа в качестве зависимости.
Один из способов предоставить Hilt информацию о привязке — это внедрение через конструктор . Используйте аннотацию @Inject
в конструкторе класса, чтобы указать Hilt, как предоставлять экземпляры этого класса:
Котлин
class AnalyticsAdapter @Inject constructor( private val service: AnalyticsService ) { ... }
Ява
public class AnalyticsAdapter { private final AnalyticsService service; @Inject AnalyticsAdapter(AnalyticsService service) { this.service = service; } ... }
Параметры аннотированного конструктора класса являются зависимостями этого класса. В этом примере AnalyticsAdapter
имеет зависимость от AnalyticsService
. Следовательно, Hilt также должен знать, как предоставлять экземпляры AnalyticsService
.
Модули рукояти
Иногда тип невозможно внедрить через конструктор. Это может произойти по нескольким причинам. Например, невозможно внедрить через конструктор интерфейс. Также невозможно внедрить через конструктор тип, которым вы не владеете, например, класс из внешней библиотеки. В этих случаях вы можете предоставить Hilt информацию о привязке, используя модули Hilt .
Модуль Hilt — это класс, аннотированный аннотацией @Module
. Как и модуль Dagger , он сообщает Hilt, как предоставлять экземпляры определённых типов. В отличие от модулей Dagger, модули Hilt необходимо аннотировать аннотацией @InstallIn
, чтобы указать Hilt, в каком классе Android каждый модуль будет использоваться или устанавливаться.
Зависимости, которые вы предоставляете в модулях Hilt, доступны во всех сгенерированных компонентах, связанных с классом Android, в который вы устанавливаете модуль Hilt.
Внедрение экземпляров интерфейса с помощью @Binds
Рассмотрим пример AnalyticsService
. Если AnalyticsService
— это интерфейс, то его нельзя внедрить через конструктор. Вместо этого предоставьте Hilt информацию о привязке, создав абстрактную функцию с аннотацией @Binds
внутри модуля Hilt.
Аннотация @Binds
сообщает Hilt, какую реализацию использовать, когда необходимо предоставить экземпляр интерфейса.
Аннотированная функция предоставляет 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 }
Ява
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 ); }
Модуль AnalyticsModule
в Hilt аннотирован @InstallIn(ActivityComponent.class)
поскольку вы хотите, чтобы Hilt внедрил эту зависимость в ExampleActivity
. Эта аннотация означает, что все зависимости в AnalyticsModule
доступны во всех активностях приложения.
Внедрение экземпляров с помощью @Provides
Интерфейсы — не единственный случай, когда невозможно внедрить тип через конструктор. Внедрение через конструктор также невозможно, если вы не являетесь владельцем класса, поскольку он взят из внешней библиотеки (например, Retrofit , OkHttpClient
или баз данных Room ), или если экземпляры должны создаваться с помощью шаблона конструктора .
Рассмотрим предыдущий пример. Если вы не являетесь прямым владельцем класса 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) } }
Ява
@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
Ява
@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() } }
Ява
@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 }
Ява
// 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 ) { ... }
Ява
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 предоставляет следующие компоненты:
Компонент рукояти | Инжектор для |
---|---|
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 ) { ... }
Ява
@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) } }
Ява
// 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 { ... }
Ява
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 ) { ... }
Ява
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 не поддерживает поставщиков контента напрямую. Если вы хотите, чтобы поставщик контента использовал Hilt для получения некоторых зависимостей, необходимо определить интерфейс с аннотацией @EntryPoint
для каждого нужного типа привязки и включить квалификаторы. Затем добавьте @InstallIn
, чтобы указать компонент, в котором будет установлена точка входа, следующим образом:
Котлин
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(); } ... }
Для доступа к точке входа используйте соответствующий статический метод из 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() ... } }
Ява
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.
Что касается кинжала, цели Hilt таковы:
- Упростить инфраструктуру Dagger для приложений Android.
- Создать стандартный набор компонентов и областей для упрощения настройки, удобочитаемости и совместного использования кода между приложениями.
- Обеспечить простой способ предоставления различных привязок к различным типам сборок, таким как тестирование, отладка или выпуск.
Поскольку операционная система Android создает множество собственных классов фреймворка, использование Dagger в приложении Android требует написания значительного объёма шаблонного кода. Hilt сокращает объём шаблонного кода, используемого при использовании Dagger в приложении Android. Hilt автоматически генерирует и предоставляет следующие элементы:
- Компоненты для интеграции классов фреймворка Android с Dagger, которые в противном случае пришлось бы создавать вручную.
- Аннотации области применения для использования с компонентами, которые Hilt генерирует автоматически.
- Предопределенные привязки для представления классов Android, таких как
Application
илиActivity
. - Предопределенные квалификаторы для представления
@ApplicationContext
и@ActivityContext
.
Код Dagger и Hilt может сосуществовать в одной кодовой базе. Однако в большинстве случаев для управления всеми процессами использования Dagger на Android лучше всего использовать Hilt. Чтобы перенести проект, использующий Dagger, в Hilt, см. руководство по миграции и практическую работу «Перенос приложения Dagger в Hilt» .
Дополнительные ресурсы
Чтобы узнать больше о Hilt, ознакомьтесь со следующими дополнительными ресурсами.
Образцы
Codelabs
Блоги
- Внедрение зависимостей в Android с помощью Hilt
- Область действия в Android и Hilt
- Добавление компонентов в иерархию Hilt
- Перенос приложения Google I/O в Hilt