Внедрение ViewModel с помощью Dagger 2 и попытка понять, почему @Binds не работает, а @Provides - - PullRequest
0 голосов
/ 19 октября 2018

Я пытаюсь добавить ViewModelProvider.Factory, и у меня возникают проблемы с пониманием, почему я не могу использовать аннотацию @Binds.

Эта аннотация работает:

@Binds
abstract ViewModelProvider.Factory bindViewModelFactory(ViewModelFactory viewModelFactory);

В сочетании со следующей аннотацией проект компилируется:

@Provides
@IntoMap
@ViewModelKey(MyViewModel.class)
static ViewModel MyViewModel(){
    return new MyViewModel();
}

Однако, если приведенный выше код заменяется следующим:

@Binds
@IntoMap
@ViewModelKey(MyViewModel.class)
abstract ViewModel bindMyViewModel(MyViewModel viewModel);

Внезапно я получаюследующее сообщение об ошибке:

... MyViewModel не может быть предоставлен без конструктора @Inject или метода с аннотацией @ Provides.

Может кто-нибудь объяснить, почему первый случайработает, а второй нет?Как я понял, @Binds должен создать класс возвращаемого типа конкретной реализации, передаваемой в качестве параметра.

1 Ответ

0 голосов
/ 20 октября 2018

Как указано в комментариях egoldx , вам нужно аннотировать конструктор MyViewModel с помощью @Inject, если вы хотите, чтобы Dagger вызывал его.Как вы упомянули, это означает, что JSR-330 определяет @Inject, чтобы иметь несколько допустимых значений :

  • Чтобы отметить конструкторы, которые система DI должна вызывать для получения экземпляра,
  • Чтобы пометить поля, которые система DI должна заполнить после создания и в существующих экземплярах, и
  • Чтобы пометить методы, вызываемые при создании / внедрении, заполнив параметры своего метода из системы DI.

Чтобы быть особенно понятным, поведение Даггера описано в Руководстве пользователя :

Используйте @Inject, чтобы комментировать конструктор, который должен использовать Даггерсоздать экземпляры класса.Когда запрашивается новый экземпляр, Dagger получит требуемые значения параметров и вызовет этот конструктор.

... противоречит определению JSR-330 @Inject в этой общедоступнойКонструкторы без параметров не могут быть вызваны:

@Inject является необязательным для общедоступных конструкторов без аргументов, когда другие конструкторы отсутствуют.Это позволяет инжекторам вызывать конструкторы по умолчанию.

Обсуждение этого отклонения происходит в хранилище Square Dagger 1, выпуск # 412 и , выпуск Google Dagger 2 # 1105 .Таким образом, дополнительная ясность была сочтена полезной (особенно учитывая количество объектов, которые вы могли бы случайно внедрить с помощью конструкторов по умолчанию), было установлено, что дополнительная стоимость добавления @Inject не слишком обременительна, и это позволяет избежать двусмысленности относительно того, являются ли подклассыимеют право на внедрение без необходимости проверять всю иерархию классов для @Inject полей.

...