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 правильно, это чаще всего единственные строки кода, которые вы найдете в моих модулях, что делает их очень удобочитаемыми.

Другие вопросы по тегам