Проблемы с внедрением вспомогательной инъекции при использовании Dagger-2 и Autofactory

#android #dependency-injection #dagger-2 #autofactory

#Android #внедрение зависимостей #dagger-2 #autofactory

Вопрос:

Я использую Dagger-2 (версия 2.7) и AutoFactory (версия 1.0-beta3). Я столкнулся со своеобразной проблемой.

У меня есть класс MyRequest, ctor которого принимает 2 параметра как:

  1. ConnectivityManager conmgr
  2. int somevalue

Я создал ctor как

 @Autofactory
public MyRequest(@Provider ConnectivityManager conmgr, int somevalue){
//
}
  

У меня есть модуль, содержащий следующее

 @Provides
@SystemScope
public final ConnectivityManager provideConnectivityManager(App app) {
return (ConnectivityManager)       
app.getSystemService(Context.CONNECTIVITY_SERVICE);
}
  

В том же модуле я делаю следующее

 @Provides
@SystemScope
public final MyRequestFactory providesMyRequestFactory(ConnectivityManager connectivityManager {
    return new MyRequestFactory(connectivityManager);
}
  

Я получаю ошибку сборки
несовместимых типов: ConnectivityManager не может быть преобразован в Provider < ConnectivityManager> .

Есть идеи, как это решить?

Ответ №1:

Как и в примере с AutoFactory, если ваш конструктор принимает a Foo , сгенерированный конструктор вашего AutoFactory примет a Provider<Foo> вместо этого. Это значит, что ваша фабрика будет запрашивать новый Foo (или ConnectivityManager ) один раз для каждого вызова get , не обязательно разделяя экземпляры между ними.

Может случиться так, что вы хотите Foo или ConnectivityManager должны быть одним и тем же экземпляром для всех экземпляров созданного объекта ( MyRequest здесь ), но это диктовать вам и Dagger, а не AutoFactory. Следовательно, AutoFactory всегда будет генерировать код, который принимает поставщиков, используете ли вы их таким образом или нет.

К счастью, исправить это очень просто: Dagger может вводить a Provider<ConnectivityManager> так же легко, как ConnectivityManager и a (как и для любой привязки), поэтому вы можете просто изменить свой @Provides метод следующим образом…

 @Provides
@SystemScope
public final MyRequestFactory providesMyRequestFactory(
        Provider<ConnectivityManager> connectivityManagerProvider {
    return new MyRequestFactory(connectivityManagerProvider);
}
  

… но поскольку ваша сгенерированная фабрика будет иметь @Inject аннотацию, вам, вероятно, было бы лучше полностью удалить @Provides метод и позволить Dagger использовать этот конструктор для MyRequestFactory инъекций. Хотя вы потеряете @SystemScope аннотацию scope из @Provides метода, это не проблема: с Provider<ConnectivityManager> помощью приведенной выше инъекции вам не нужно беспокоиться о жизненном цикле сгенерированной фабрики, поэтому вы можете вернуться к нераскрытому предоставлению по умолчанию.

Комментарии:

1. Спасибо за хорошее объяснение. И по уважительным причинам, почему мне не нужен «@Provides» для «MyRequest». Однако вы могли бы дать представление о том, как Dagger-2 будет вводить Provider<ConnectivityManager>, хотя я предоставляю только ConnectivityManger, используя «@Provides ConnectivityManager» в моем модуле (а не Provider <ConnectivityManager>

2. @shyguy Добро пожаловать! И вам, вероятно, понадобится @Provides для MyRequest, но не для MyRequestFactory. Вы можете ознакомиться с разделом «Привязки на графике» в Руководстве пользователя Dagger 2 для получения подробной информации, но достаточно сказать, что Dagger будет обрабатывать запросы для Provider<T> Lazy<T> , или даже Provider<Lazy<T>> для любого T , который вы предоставляете с помощью @Provides метода или иным образом.

3. Извините за опечатку, я имел в виду только MyRequestFactory. Я обязательно перейду по предложенной вами ссылке. Еще раз спасибо @Jeff Bowman