Skip to content

Latest commit

 

History

History
178 lines (122 loc) · 11.4 KB

README.md

File metadata and controls

178 lines (122 loc) · 11.4 KB

DI Dependency Injection / Внедрение зависимостей - Dagger2 Hilt


Dependency Injection (DI) — Внедрение зависимостей

DI — это паттерн проектирования, который позволяет передавать зависимости (объекты, сервисы) в класс извне, вместо того чтобы создавать их внутри класса. Это делает код более гибким, тестируемым и поддерживаемым.

  • Dagger 2Java библиотека для реализации подхода DI (Dependency Injection/внедрение зависимостей).
  • Hilt – обёртка над Dagger под Android, чтобы уменьшить количество шаблонного кода.

Основные понятия DI

  • Зависимость (Dependency) - Это объект, который требуется другому объекту для работы. Например, Repository — это зависимость для ViewModel.
  • Внедрение (Injection) - Процесс передачи зависимости в класс. Это может быть сделано через конструктор, метод или поле.
  • Контейнер зависимостей (Dependency Container) - Объект, который управляет созданием и предоставлением зависимостей.

Factory

Factory - Паттерн, который создает объекты без указания конкретного класса. В DI фабрики используются для создания зависимостей.


Dagger2

Dagger2 - Фреймворк для реализации DI в Android. Он генерирует код на этапе компиляции, что делает его быстрым и безопасным.

Основные компоненты:

  • Модули (@Module) — Классы, которые предоставляют зависимости.
  • Компоненты (@Component) — Связывают модули и внедряют зависимости.
  • Аннотации:
    • @Inject — Запрашивает зависимость.
    • @Provides — Предоставляет зависимость в модуле.
    • @Singleton — Ограничивает время жизни зависимости.

Hilt

Hilt - Упрощенная версия Dagger, разработанная специально для Android. Hilt автоматически генерирует большую часть кода, что упрощает настройку DI.

Основные аннотации:

  • @HiltAndroidApp — Применяется к классу Application, чтобы включить Hilt.
  • @AndroidEntryPoint — Внедряет зависимости в Android-компоненты (Activity, Fragment, ViewModel и т.д.).
  • @Module — Определяет модули для предоставления зависимостей.
  • @InstallIn — Указывает, к какому компоненту (например, SingletonComponent) привязан модуль.
  • @Provides — Предоставляет зависимость в модуле.
  • @Binds — Связывает интерфейс с его реализацией.
  • @Inject — Запрашивает зависимость.
  • @HiltViewModel — Внедряет зависимости в ViewModel.
  • @AssistedInject и @Assisted — Используются для зависимостей, которые требуют параметров во время создания.

Для корректной работы необходимо пометить данные классы аннотациями:

  • @AndroidEntryPointActivity, Fragment, Service, View, Broadcast Receiver
  • @HiltAndroidAppApplication
  • @HiltViewModelViewModel

Чтобы Dagger научился создавать объект и сгенерировал для него фабрику, достаточно указать аннотацию @Inject у конструктора.

Если у нас нет доступа к конструктору, либо мы работаем с интерфейсами, потребуется создать класс с аннотацией @Module и в нём описать как данные зависимости получать. Если мы связываем интерфейс и реализацию, нам понадобится interface, если нет, то class.

Для связи интерфейса и реализации используется аннотация @Binds.

Требования:

  • параметр должен быть наследником возвращаемого интерфейса
  • наличие аннотации @Inject у параметра в конструкторе

Если мы не можем модифицировать конструктор, то используем аннотацию @Provides и создаём зависимость руками. В таком случае модуль должен быть классом.

Чтобы проект скомпилировался, нужно у каждого модуля проставить аннотацию @InstallIn. Внутри InstallIn нужно указать на каком уровне модуль будет установлен:

  • SingletonComponent
  • ActivityComponent
  • ActivityRetainedComponent
  • FragmentComponent
  • ServiceComponent
  • ViewComponent
  • ViewModelComponent
  • ViewWithFragmentComponent

В случае, если нам нужно часть данных передать вручную при вызове фабричной функции, мы можем поставить @AssistedInject вместо @Inject. То, что передаётся извне помечаем @Assisted.


Scopes (Области видимости)

Scopes - Области видимости определяют время жизни зависимостей. Внутри модулей можно привязать объекты к жизненному циклу компонентов.

Например, зависимость с областью видимости @Singleton будет существовать всё время жизни приложения.

Основные области:

  • @Singleton — Время жизни приложения.

  • @ActivityScoped — Время жизни Activity.

  • @ViewModelScoped — Время жизни ViewModel.

  • @FragmentScoped — Время жизни Fragment.

  • SingletonComponent@Singleton

  • ActivityComponent@ActivityScoped

  • ActivityRetainedComponent@ActivityRetainedScoped

  • FragmentComponent@FragmentScoped

  • ServiceComponent@ServiceScoped

  • ViewComponent, ViewWithFragmentComponent@ViewScoped

  • ViewModelComponent@ViewModelScoped


Класс App — Основной класс приложения

Класс App — это класс, который наследуется от Application и является точкой входа для инициализации контейнера зависимостей в Hilt. Он предоставляет доступ к зависимостям на уровне всего приложения.

/**
 * Основной класс приложения, который предоставляет контейнер зависимостей.
 * Этот класс реализует интерфейс [DependencyContainerProvider] для предоставления
 * экземпляра [DependencyContainerImpl], который содержит все зависимости приложения.
 *
 * @see DependencyContainerProvider
 * @see DependencyContainerImpl
 */
@HiltAndroidApp
class App : Application()

Зачем нужен?

  • Инициализация Hilt - Класс App используется для инициализации Hilt, чтобы он мог управлять зависимостями на уровне приложения.
  • Глобальные зависимости - Здесь можно предоставить зависимости, которые должны существовать всё время жизни приложения (например, база данных, репозиторий, API-клиент).
  • Контейнер зависимостей - Hilt автоматически создает контейнер зависимостей, который управляет временем жизни объектов.

Как это работает?

  • Аннотация @HiltAndroidApp - Эта аннотация применяется к классу App, чтобы Hilt сгенерировал необходимый код для работы DI.
  • Контейнер зависимостей - Hilt создает контейнер зависимостей, который автоматически предоставляет зависимости в Activity, Fragment, ViewModel и другие компоненты.

Что происходит под капотом?

  • Генерация компонентов - Hilt генерирует компоненты (например, SingletonComponent), которые управляют зависимостями.
  • Инициализация контейнера - При запуске приложения Hilt инициализирует контейнер зависимостей, который доступен всему приложению.
  • Внедрение зависимостей - Hilt автоматически внедряет зависимости в классы, помеченные аннотациями (например, @AndroidEntryPoint).

Кратко

  • DI — Паттерн для управления зависимостями, делающий код гибким и тестируемым.
  • Factory — Паттерн для создания объектов.
  • Dagger2 — Мощный фреймворк для DI с генерацией кода на этапе компиляции.
  • Hilt — Упрощенная версия Dagger для Android.
  • Scopes — Определяют время жизни зависимостей (например, @Singleton, @ActivityScoped).
  • Класс App — Основной класс приложения, который инициализирует Hilt и предоставляет контейнер зависимостей.

Основные аннотации Hilt:

@HiltAndroidApp, @AndroidEntryPoint, @Module, @InstallIn, @Provides, @Binds, @Inject, @HiltViewModel, @AssistedInject, @Assisted.