В чем разница между аннотациями @Provides и @Binds в Dagger 2
Что проверяют
Понимаете ли вы, что одна создаёт объект, а другая только связывает типы, и знаете ли выгоду второй.
Как отвечать
@Provides помечает метод модуля с телом, который сам создаёт и возвращает объект. Нужен, когда объект надо собрать вручную: класс из чужой библиотеки, которому нельзя добавить @Inject, объект с параметрами конфигурации, результат построителя.
@Provides
fun provideRetrofit(client: OkHttpClient): Retrofit =
Retrofit.Builder().baseUrl(BASE_URL).client(client).build()@Binds помечает абстрактный метод без тела, который просто говорит: когда просят интерфейс, подставь вот эту реализацию. У реализации при этом уже должен быть конструктор с @Inject.
@Binds
abstract fun bindJobRepository(impl: JobRepositoryImpl): JobRepositoryЗачем нужен @Binds, если то же можно написать через @Provides: он эффективнее. Для @Provides Dagger генерирует класс-фабрику, вызывающий ваш метод, а для @Binds подстановка происходит напрямую, без лишнего кода. На большом графе это заметно и по размеру приложения, и по времени сборки.
Требования к @Binds:
- метод абстрактный, значит модуль это интерфейс или абстрактный класс;
- ровно один параметр;
- тип возвращаемого значения должен быть супертипом параметра.
Практическая тонкость при смешивании: если в одном абстрактном модуле есть и @Binds, и @Provides, то методы с @Provides должны быть статическими, иначе Dagger потребует экземпляр модуля. В Kotlin это companion object с @JvmStatic либо вынос в отдельный объект.
Правило выбора: связываете интерфейс со своей реализацией это @Binds, создаёте объект руками это @Provides.
Где спотыкаются
Пишут @Binds в обычном классе, а не в абстрактном.
Не помечают @Provides статическим и получают ошибку сборки.
Используют @Provides для простой привязки интерфейса и раздувают сгенерированный код.
Забывают @Inject на конструкторе реализации.