Внедрение зависимостей с Dagger 2
Внедрение зависимостей (dependency injection) — приём, при котором объект не создаёт свои зависимости сам, а получает их снаружи. Dagger 2 — самый распространённый DI-фреймворк для Android, и его главная особенность в том, что весь граф зависимостей он собирает на этапе компиляции, генерируя обычный Kotlin/Java-код без всякой рефлексии. Отсюда его скорость и отсутствие рантайм-сюрпризов.
Ловушек тут три, и все — про непонимание, кто за что отвечает. @Module описывает, КАК создавать объекты, а @Component связывает модули в граф и выдаёт результат. @Binds и @Provides оба объявляют привязку, но @Binds — тоньше. А multibinding не переопределяет привязки, а собирает их в коллекцию. Полная карта — в слоях ниже.
Карта темы
- Component и Module —
@Moduleпоставляет рецепты,@Componentсвязывает их в граф и служит точкой входа инъекции. - Binds и Provides — конкретный фабричный
@Providesпротив абстрактного@Binds, связывающего интерфейс с реализацией. - Multibinding —
@IntoSetи@IntoMapсобирают вклад многих модулей в один инъектируемыйSet/Map.
Частые ошибки и ловушки
| Ошибка | Последствие |
|---|---|
Менять роли @Component и @Module местами | Неверная ментальная модель — не соберёте граф правильно |
| Считать, что Dagger строит граф рефлексией в рантайме | Упускаете, что всё генерируется при компиляции — ошибки видны сразу |
Писать тело @Provides, которое просто возвращает параметр | Лишняя пустая фабрика там, где уместнее @Binds |
Делать метод @Binds конкретным | Не скомпилируется — @Binds обязан быть абстрактным |
| Думать, что multibinding переопределяет привязки | На деле он агрегирует их в Set/Map, ничего не отбрасывая |
Не перечислить @Module в @Component | Модуль не попадёт в граф — зависимость не найдётся |
Значение для собеседований
Тему спрашивают как проверку того, отделяете ли вы «как создавать» (модуль) от «как связать и выдать» (компонент), и понимаете ли, что Dagger — кодогенератор, а не рантайм-контейнер. Кандидат, который говорит «@Component — это интерфейс, из которого Dagger генерирует реализацию графа при компиляции», сразу опережает «ну, это где висят аннотации».
Что обычно проверяют:
- Роли
@Componentи@Moduleи почему модуль надо перечислить в компоненте. - Разницу
@Bindsи@Providesи когда какой тоньше. - Что Dagger генерирует код при компиляции, а не резолвит рефлексией.
- Зачем нужен multibinding и что он агрегирует, а не переопределяет.
Типичный неверный ответ: «Dagger в рантайме через рефлексию собирает синглтоны в общий реестр». На деле граф — это сгенерированный при компиляции код (DaggerAppComponent), а неразрешённая зависимость обернётся ошибкой сборки, а не падением в рантайме.