Якщо ви розробляєте додатки для Android, ви, ймовірно, стикалися з необхідністю краще організувати свої класи, щоб запобігти повному хаосу проекту. Саме тут і з'являється впровадження залежностей – шаблон проектування, який, хоча спочатку може здатися чорною магією, по суті є способом забезпечити кожен клас необхідними йому об'єктами без необхідності створювати їх самим класом.
Hilt з'являється, щоб врятувати нас від складнощів Dagger, пропонуючи верхній рівень, який стандартизує вставку залежностей . Завдяки інтеграції з Jetpack, Hilt автоматично керує контейнерами та життєвими циклами, дозволяючи нам зосередитися на бізнес-логіці, а не переміщувати об'єкти, як під час переїзду.
Початкова конфігурація середовища
Щоб розпочати роботу з Hilt, першим кроком є підготовка середовища Gradle. Важливо додати hilt-android-gradle-plugin до файлу конфігурації вашого проекту. Потім у файлі модуля вашої програми вам потрібно застосувати плагін та додати відповідні залежності, переконавшись, що компілятор (незалежно від того, чи використовується kapt, чи KSP) налаштовано правильно.
Одна важлива деталь полягає в тому, що для безперебійної роботи проєкт має бути налаштований на використання Java 17 (або Java 8 для старіших версій), оскільки це є необхідною умовою для безперебійної спільної роботи Hilt та Jetpack Compose . Якщо ви помітили, що програма не компілюється після активації плагіна, перевірте ще раз, чи точно збігаються версії Kotlin та KSP, оскільки навіть незначна розбіжність може порушити весь процес компіляції.
Серце Хілта: Клас застосування
Будь-який застосунок, який хоче скористатися перевагами цієї бібліотеки, повинен мати власний клас Application. Простого його створення недостатньо; його потрібно позначити анотацією @HiltAndroidApp . Цей рядок запускає генерацію коду Hilt та створює кореневий контейнер застосунку.
Цей компонент верхнього рівня є життєво важливим, оскільки він пов'язаний із загальним життєвим циклом програми та служить основою для всіх інших компонентів , щоб вони могли отримати доступ до залежностей, визначених на цьому рівні. Звичайно, не забудьте зареєструвати цей клас у файлі AndroidManifest.xml за допомогою атрибута name, інакше Hilt залишиться повністю непоміченим.
Впровадження залежностей у компоненти Android
Щойно застосунок готовий, ми можемо почати впроваджувати залежності в активності, фрагменти, представлення або сервіси. Для цього ми використовуємо анотацію @AndroidEntryPoint . Це повідомляє Hilt, що цей клас є точкою входу, і що для нього слід згенерувати окремий компонент.
Коли ми хочемо отримати певну залежність всередині активності, ми використовуємо впровадження полів через анотацію @Inject. Дуже важливо пам'ятати, що ці поля не можуть бути приватними ; якщо ви спробуєте використати модифікатор private, компілятор без вагань видасть помилку. У випадку Jetpack Compose, проста анотація кореневої активності дозволяє нам отримати доступ до ViewModels безпосередньо всередині компонованих функцій.
Стратегії визначення зв'язків
Hilt потрібно знати, як створювати запитувані нами об'єкти. Найпряміший спосіб – це ін'єкція конструктора , де ми розміщуємо `@Inject` безпосередньо перед конструктором класу. Це дозволяє Hilt аналізувати параметри та визначати, як забезпечити кожну з цих залежностей.
Однак, бувають випадки, коли ми не маємо повного контролю над класом, наприклад, під час використання зовнішніх бібліотек, таких як Retrofit або OkHttpClient. Саме тут на допомогу приходять модулі Hilt . Модуль — це клас, анотований за допомогою @Module, який повинен містити @InstallIn, щоб вказати, який компонент повинен містити цю залежність.
- Використання @Provides: Це використовується, коли клас є стороннім або вимагає складного шаблону побудови. Тут ми визначаємо функцію, яка повертає необхідний екземпляр.
- Використання @Binds: Це ідеальний варіант, коли ми хочемо пов'язати інтерфейс з конкретною реалізацією. Він визначається як абстрактна функція, яка каже Hilt: «коли хтось запитує цей інтерфейс, надайте йому цю реалізацію».
Управління обсягом та життєвим циклом
За замовчуванням Hilt створює новий екземпляр щоразу, коли запитується залежність. Однак іноді нам потрібно, щоб об'єкт залишався незмінним протягом усього життя програми або екрана. Для цього ми використовуємо області видимості компонентів.
Якщо ми позначимо клас за допомогою @Singleton та встановимо його в SingletonComponent, у нас буде один глобальний екземпляр. Якщо ми бажаємо, щоб об'єкт існував лише протягом тривалості дії, ми використовуємо @ActivityScoped всередині ActivityComponent. Вкрай важливо не зловживати областями видимості, оскільки занадто тривале зберігання об'єктів у пам'яті може негативно вплинути на продуктивність програми.
Особливі випадки та кваліфікатори
Іноді нам потрібно впровадити дві різні реалізації одного й того ж інтерфейсу. Щоб уникнути перевантаження компілятора, ми використовуємо кваліфікатори . Кваліфікатор — це, по суті, власна анотація, яка використовується для позначення певного зв'язування, що дозволяє нам розрізняти, наприклад, HTTP-клієнт для автентифікації та клієнт для загальних запитів.
Крім того, Hilt спрощує роботу за допомогою попередньо визначених кваліфікаторів, таких як @ApplicationContext та @ActivityContext, що дозволяє нам отримувати контекст Android без необхідності вручну налаштовувати модулі. Нарешті, для класів, які Hilt не підтримує нативно (наприклад, ContentProviders), ми можемо використовувати анотацію @EntryPoint , створюючи ручний міст для вилучення залежностей з графа Hilt. Поділіться цією інформацією, щоб більше користувачів могли дізнатися про неї.