ViewModel — это компонент из набора библиотек под названием Android Architecture Components, которые были представлены на Google I/O 2017. ViewModel — предназначена для хранения и управления данными связанных с представлением, а также с возможностью “пережить” пересоздание активити (например переворот экрана).  На Хабре уже была хорошая статья посвящена ViewModel, где можно ознакомится с данной темой более детально.  В данной статье будет рассмотрены варианты инжекта(предоставление) зависимостей в компонент ViewModel с использованием Dagger 2. Проблема заключается в том, что получение ViewModel должно осуществляться специальным образом, что в свою очередь накладывает некоторые ограничения, которые связанные с предоставлением зависимостей в сам класс ViewModel, а также предоставление ViewModel в качестве зависимости. Данная статья также возможно будет интересна тем, кто интересуется практическим применением такой функциональности Dagger, как multibinding.  Специальный способ получение ViewModel заключается в следующем: В начале мы должны получить ViewModelProvider, который будет связан с активити или фрагментом, так же это определяет время жизни ViewModel. Второй параметр служит для указания фабрики, которая будет использоваться для создания инстанса ViewModel, не является обязательным, если мы его не указываем, будет использоваться фабрика по умолчанию. Фабрика по умолчанию поддерживает создание инстанса классов, которые являются наследниками ViewModel(с конструктором без аргументов) и классов, которые являются наследниками AndroidViewModel(c конструктором с одним аргументом — тип Application).  Если мы хотим создать инстанс ViewModel с собственными аргументами в конструкторе (которые не поддерживаются фабрикой по умолчанию), то нам необходимо реализовать собственную фабрику. После того, как получили ViewModelProvider, мы уже можем получить ViewModel: Из вышеперечисленного описания следует: Предоставить зависимости в ViewModel можно разными способами и каждого из способов есть свои плюсы и минусы, поэтому будет рассмотрены несколько вариантов. Начнем с определения модуля и сабкомпонента, которые будут использоваться для инжекта в активити: Наличие такого модуля и сабкомпонента дает нам возможность запросить вью модель через @Inject вместо ViewModelProviders.of(activity).get(ProductViewModel.class) внутри нашей активити.  При использовании фабрики по умолчанию, созданием инстансов наших ViewModel будет заниматься эта фабрика и мы не можем запрашивать зависимости в ViewModel через конструктор, поэтому будем инжектить зависимости через компонент. Для того чтобы не засорять root компонент создадим сабкомпонент специально для вью моделей. Определим наш root компонент:  AppModule — будет содержать зависимости, которые нужны будут нашим вью моделям(например ProductDetailsFacade). Создадим Application, который будет содержать в себе root компонент и сабкомпонент для вью моделей: Теперь мы можем заинжектить зависимости в ViewModel: Вместо инжекта можно использовать provide методы у компонента. Инжект ViewModel в активити: Преимущества данного способа: Недостатки: Создадим пару вью моделей, где будем предоставлять зависимости через конструктор: Создадим собственную аннотацию ключа, которые мы будем использовать для байндинга наших вью моделей в коллекцию для использования мультибайндинга. Про мультибайндиг можно почитать здесь. Определим модуль, где мы будем байндить в коллекцию наши вью модели: Перейдем к написанию нашей фабрики по предоставлению ViewModel с использованием мультибайндинга: Provider<ViewModel> дает нам возможность использовать отложенную инициализацию вью модели, а также получение каждый раз нового инстанса вью модели.
Без мультибайндинга у нас мог бы быть огромный блок из if/else. Класс Application: Предоставление ViewModel в наше активити: Преимущества данного способа: Недостатки: Если бы мы запрашивали модель через @Inject, то мы бы просто получили инстанс вью модели (т.к. она уже находится в графе зависимостей) и она бы никак не была бы связана с жизненным циклом активити или фрагментом и не смогла бы “пережить” например переворот экрана.Чтобы это работало нам необходимо, чтобы создание происходило через фабрику.
Мы не можем дважды добавить в граф вью модели, т.е. мы не можем сделать следующее: Для обхода данного ограничения можно ввести интерфейс для модели и запрашивать вью модель по интерфейсу: На момент написания статьи использовался dagger 2.11 и архитектурные компоненты версии 1.0.0-alpha9. Как вы могли заметить архитектурные компоненты на момент написания статьи имеют альфа версию. Возможно в будущем появятся и другие методы получения вью модели. Java EE, Android