Будущих учащихся на курсе "Android Developer. Professional" приглашаем посетить открытый урок на тему "Пишем Gradle Plugin"
А также делимся переводом полезной статьи.
Простой способ использовать внедрение зависимостей в приложениях для Android
Hilt это новая библиотека для внедрения зависимостей, построенная на основеDagger. Она позволяет использовать возможности Dagger в приложениях для Android упрощенным способом. В этом руководстве описаны основные функциональные возможности библиотеки и приведено несколько фрагментов кода, которые помогут вам начать использовать Hilt в своих проектах.
Настройка Hilt
Чтобы настроить Hilt в своем приложении, сначала выполните указания из руководства: Установка Gradle Build.
После установки всех необходимых элементов и подключаемых
модулей, чтобы использовать Hilt, задайте своему
классуApplicationаннотацию@HiltAndroidApp.
Больше
ничего делать не нужно, а также не нужно вызывать Hilt
напрямую.
Определение и внедрение зависимостей
При написании кода, в котором используется внедрение зависимостей, есть два основных компонента, которые следует учитывать:
-
Классы, имеющие зависимости, которые вы собираетесь внедрить.
-
Классы, которые могут быть внедрены как зависимости.
Они не являются взаимоисключающими: во многих случаях класс одновременно является внедряемым и имеет зависимости.
Как сделать зависимость внедряемой
Чтобы в Hilt сделать объект внедряемым, необходимо указать для Hilt способ создания экземпляра этого объекта. Такие инструкции называютсяпривязками.
Есть три способа определения привязки в Hilt.
-
Добавить к конструктору аннотацию
@Inject
-
Использовать
@Binds
в модуле -
Использовать
@Provides
в модуле
Добавление к конструктору
аннотации@Inject
У любого класса может быть конструктор с
аннотацией@Inject
, что позволяет использовать его в
качестве зависимости в любом месте проекта.
Использование модуля
Два других способа преобразования объектов во внедряемые в Hilt связаны с использованием модулей.
Модуль Hiltможно считать набором рецептов, указывающих Hilt, как создать экземпляр того или иного объекта, у которого нет конструктора, например, интерфейса или системной службы.
Кроме того, в тестах любой модуль можно заменить другим модулем. Например, это позволяет легко заменять реализации интерфейсов мок-объектами.
Модули устанавливаются вкомпонент
Hilt, который указывается с помощью
аннотации@InstallIn
. Я дам более подробное объяснение
ниже.
Вариант 1: использовать@Binds, чтобы создать привязку для интерфейса
Если вы хотите использовать в своем кодеOatMilk, когда
требуетсяMilk, создайте абстрактный метод внутри модуля и задайте
ему аннотацию@Binds
. Обращаю внимание, чтобы этот
вариант работал, сам OatMilk должен быть внедряемым. Для этого его
конструктору необходимо задать аннотацию@Inject
.
Вариант 2: создать функцию-фабрику с
помощью@Provides
Когда экземпляр нельзя сконструировать напрямую, можно создать поставщик. Поставщик это функция-фабрика, которая возвращает экземпляр объекта.
В качестве примера можно привести системную службу, скажемConnectivityManager, которую необходимо получить из контекста.
ОбъектContextявляется внедряемым по умолчанию, если задать ему
аннотацию@ApplicationContext
либо@ActivityContext
.
Внедрение зависимости
После того как вы сделали нужные зависимости внедряемыми, их можно внедрять с помощью Hilt двумя способами.
-
Как параметры конструктора
-
Как поля
Как параметры конструктора
Если пометить конструктор аннотацией @Inject
, Hilt
внедрит все параметры в соответствии с привязками, которые вы
определили для этих типов.
Как поля
Если класс является точкой входа, указанной с использованием
аннотации@AndroidEntryPoint
(подробнее об этом
рассказано в следующем разделе), внедрены будут все поля,
помеченные аннотацией@Inject
.
Поля, помеченные аннотацией@Inject
,должны быть
общедоступными. Также удобно пометить их модификатором lateinit,
чтобы не пришлось обеспечивать поддержку ими пустого значения,
поскольку перед внедрением они имеют исходное
значениеnull
.
Обратите внимание, внедрять зависимости как поля стоит только
тогда, когда у класса должен быть конструктор без параметров,
напримерActivity
. В большинстве случаев рекомендуется
внедрять зависимости посредством параметров конструктора.
Прочие важные понятия
Точка входа
Помните, я сказал, что во многих случаях класс создается путем внедренияиимеет зависимости, внедренные в него? В некоторых случаях у вас будет класс, который несоздаетсяпутем внедрения зависимости, но имеет зависимости, внедренные в него. Хорошим примером этого являются активности, которые в стандартной ситуации создаются платформой Android, а не библиотекой Hilt.
Эти классы являютсяточками входав график зависимостей Hilt, а Hilt необходимо знать, что у них есть зависимости, требующие внедрения.
Точка входа Android
Большинство ваших точек входа будут так называемымиточками входа Android:
-
Activity
-
Fragment
-
View
-
Service
-
BroadcastReceiver
Если это так, такой точке входа следует задать
аннотацию@AndroidEntryPoint
.
Другие точки входа
Большинству приложений обычно нужны только точки входа Android, но если вы взаимодействуете с библиотеками, не работающими с Dagger, или с компонентами Android, которые пока не поддерживаются в Hilt, то вам может потребоваться создать собственную точку входа для доступа к графику Hilt вручную. Можете ознакомиться с инструкциями по преобразованию произвольных классов в точки входа.
ViewModel
ViewModel это особый случай: экземпляры этого класса не
создаются напрямую, так как они должны создаваться платформой, при
этом он также не является точкой входа Android. Вместо этого с
классамиViewModel
используют специальную
аннотацию@ViewModelInject
, которая позволяет Hilt
внедрять в них зависимости, когда они создаются с помощью
выраженияby viewModels()
. Это похоже на то,
как@Inject
работает для других классов.
Если вам требуется доступ к состоянию, сохраняемому в классе
ViewModel
, внедритеSavedStateHandleв
качестве параметра конструктора, добавив
аннотацию@Assisted
.
Чтобы использовать@ViewModelInject
, вам нужно будет
добавить еще несколько зависимостей. Дополнительные сведения см. в
статье:
Интеграции Hilt и Jetpack.
Компоненты
Каждый модуль устанавливается внутрикомпонента
Hilt, который указывается с помощью
аннотации@InstallIn
(<компонент>).
Компонент модуля используется главным образом для предотвращения
случайного внедрения зависимости не в том месте. Например,
аннотация
@InstallIn
(ServiceComponent.class
) не
позволит использовать привязки и поставщики, имеющиеся в
соответствующем модуле, внутри активности.
Кроме того, использование привязки можно ограничить пределами компонента, в котором находится модуль. Что приводит меня к
Области
По умолчанию у привязок нет областей. В приведенном выше примере
это означает, что каждый раз, когда вы внедряетеMilk, вы получаете
новый экземплярOatMilk. Если добавить
аннотацию@ActivityScoped
,область использования
привязки будет ограничена пределами
ActivityComponent
.
Теперь, когда у модуля есть область действия, Hilt будет
создавать только одинOatMilkна экземпляр активности. Кроме того,
этот экземплярOatMilkбудет привязан к жизненному циклу этой
активности он будет создаваться при
вызовеonCreate()
активности и уничтожаться при
вызовеonDestroy()
активности.
В этом случае иmilk, иmoreMilkбудут указывать на один и тот же экземплярOatMilk. Однако, если у вас несколько экземпляровLatteActivity, у каждого из них будет собственный экземплярOatMilk.
Соответственно, у других зависимостей, внедренных в эту активность, будет та же область, поэтому они тоже будут использовать тот же экземплярOatMilk:
Область зависит от компонента, в который установлен ваш модуль.
Например,@ActivityScoped
можно применить только к
привязкам, находящимся внутри модуля, который установлен
внутриActivityComponent
.
Область также определяет жизненный цикл внедренных экземпляров:
в данном случае одиночный экземплярMilk,
используемыйFridgeиLatteActivity, создается,
когдаonCreate()
вызывается дляLatteActivity, и
уничтожается в егоonDestroy()
. Это также означает, что
нашMilkне переживет изменение конфигурации, поскольку при этом
вызываетсяonDestroy()
для активности. Преодолеть это
можно путем использования области с более длительным жизненным
циклом, например@ActivityRetainedScope
.
Список имеющихся областей, компонентов, которым они соответствуют, и жизненных циклов, которым они следуют, приведен в статье:Компоненты Hilt.
Внедрение поставщика
Иногда требуется более прямой контроль над созданием внедренных экземпляров. Например, вам требуется, чтобы один или несколько экземпляров какого-то объекта внедрялись только тогда, когда они нужны, в соответствии с бизнес-логикой. В этом случае можно использоватьdagger.Provider.
Внедрение поставщика можно использовать независимо от того, чем
является зависимость и как она внедряется. Любой объект, который
можно внедрить, можно обернуть вProvider<>
,
чтобы для него использовалось внедрение поставщика.
Фреймворки внедрения зависимостей (такие как Dagger иGuice) обычно применяются в крупномасштабных, сложных проектах. В то же время библиотека Hilt, будучи простой в освоении и настройке, предоставляет все возможности Dagger в пакете, который можно использовать в приложениях любого типа, независимо от размеров кодовой базы.
Если хотите поближе познакомиться с библиотекой Hilt и принципами ее работы, а также узнать о других ее возможностях, которые могут оказаться вам полезными, отправляйтесь наее официальный веб-сайт, где приведен подробный обзор и справочная документация.
Узнать подробнее о курсе "Android Developer. Professional"
Записаться на открытый урок "Пишем Gradle Plugin"
Прямо сейчас вOTUSстартовалановогодняя распродажа. Скидка распространяется абсолютно на все курсы. Сделайте подарок себе или близким -переходите на сайти забирайте курс со скидкой. А в качестве бонуса предлагаем зарегистрироваться на абсолютнобесплатные демо-уроки: