Dagger 2 - как избежать повторения кода для внедрения зависимостей, которые требуют контекста активности
В проекте, над которым я работаю, есть ряд служебных классов, для которых требуется контекст активности.
Я не хочу объявлять новый метод @Provides для каждого действия, которое использует зависимость. т.е. я не хочу этого:
@Provides
static Navigator providesNavigator(ActivityOne activity) {
returns new Navigator(activity);
}
// ...and in another module
@Provides
static Navigator providesNavigator(ActivityTwo activity) {
returns new Navigator(activity);
}
Поэтому вместо этого я объявляю эти утилиты в едином модуле ActivityUtilitiesModule и передаю нашу базовую активность, которую расширяют все остальные действия. Теперь мне не нужно объявлять мою зависимость от Navigator x раз.
@Provides
static Navigator(BaseActivity activity) {
return new Navigator(activity);
}
Однако Даггер не знает, как удовлетворить зависимость от BaseActivity. Это означает, что для каждого действия мне нужно создать метод предоставляет, который будет удовлетворять зависимости BaseActivity с конкретным используемым действием. например:
@Provides
static BaseActivity providesBaseActivity(ActivityOne activity) {
return activity;
}
Это лучше - мне нужно только повторять этого одного провайдера для каждого действия, а не повторять провайдера для каждого класса утилит для каждого действия, но это все еще выглядит как нежелательный дополнительный шаг в настройке Dagger, и еще одна вещь, которая делает код труднее Понимаю.
Есть ли шаблон, который позволяет мне избежать необходимости предоставлять этого поставщика BaseActivity для каждого вида деятельности?
1 ответ
Пожалуйста, используйте Constructor Injection. имеющий provide*
методы, которые вызывают только конструктор, - это только шум и код для поддержки. добавлять @Inject
в конструктор класса и возможные области видимости на класс.
@SomePossibleScope
class Navigator {
@Inject
Navigator(Activity activity) { }
}
Если вы сделаете это, вам, вероятно, вообще не понадобится ваш ActivityUtilitiesModule.
Если ваш класс зависит от Activity
или же BaseActivity
тогда вам нужно это предоставить. И да, вам придется как-то рассказать об этом Даггеру.
Если вы должны использовать абстрактный класс или интерфейс, вы должны использовать @Binds
вместо.
@Binds BaseActivity bindsBaseActivity(ActivityOne activity);
По сравнению с @Provides
Dagger может оптимизировать этот код дальше, сократив количество вызовов методов и созданий объектов, а также несколько меньше строк кода.
Я не знаю, почему ваши Utils зависят от Activity
, но если бы они только нужны Context
тогда вы могли бы просто предоставить им контекст приложения без необходимости связывать или предоставлять вашу фактическую активность.
Я лично просто привязываю текущую активность к типам, которые она реализует, используя приведенный выше синтаксис. И если вы используете Constructor Injection правильно, это чаще всего единственные строки кода, которые вы найдете в моих модулях, что делает их очень удобочитаемыми.