Hilt — это библиотека внедрения зависимостей для Android, которая упрощает шаблонное внедрение зависимостей вручную в ваш проект. Выполнение внедрения зависимостей вручную требует от вас создания каждого класса и его зависимостей вручную, а также использования контейнеров для повторного использования и управления зависимостями.
Hilt предоставляет стандартный способ использования внедрения зависимостей в вашем приложении, предоставляя контейнеры для каждого класса Android в вашем проекте и автоматически управляя их жизненными циклами. Hilt построен на основе популярной библиотеки DI Dagger, чтобы получить преимущества от корректности времени компиляции, производительности во время выполнения, масштабируемости и поддержки Android Studio , которые обеспечивает Dagger. Для получения дополнительной информации см. Рукоять и Кинжал .
В этом руководстве объясняются основные концепции Hilt и созданных им контейнеров. Он также включает демонстрацию того, как загрузить существующее приложение для использования Hilt.
Добавление зависимостей
Сначала добавьте плагин hilt-android-gradle-plugin
в корневой файл build.gradle
вашего проекта:
классный
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 }
Затем примените плагин Gradle и добавьте эти зависимости в файл 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 использует функции 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 ); }
Модуль Hilt AnalyticsModule
помечен аннотацией @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 для получения некоторых зависимостей, вам необходимо определить интерфейс с аннотацией @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.
В отношении 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, см. руководство по миграции и лабораторную работу «Миграция вашего приложения Dagger на Hilt» .
Дополнительные ресурсы
Чтобы узнать больше о Hilt, посетите следующие дополнительные ресурсы.
Образцы
Кодлабы
Блоги
- Внедрение зависимостей на Android с помощью Hilt
- Определение области действия в Android и Hilt
- Добавление компонентов в иерархию Hilt
- Перенос приложения Google I/O в Hilt