ViewModel for Fragment вместо доступа к Activity ViewModel?

Проблема довольно проста. Вопрос в том, что касается использования ViewModels, LiveData и других связанных с Lifecycle арочных подходов.
У меня есть активность с NavDrawer, который переключает фрагменты внутри.
А также у меня есть случай, когда на экране одновременно присутствуют два фрагмента - это будет основной болью. Один фрагмент имеет ViewPager с вложенными Fragments (не спрашивайте почему). Другой фрагмент просто получает информацию от первого, когда пользователь выполняет некоторые действия. Это достигается просто путем совместного использования активности viewmodel. Но само приложение имеет много бизнес-логики, и по мере продвижения модель представления становится все больше и больше.
То, что я хочу спросить - не квитанция или правила, как это исправить, или, может быть, как преодолеть это, исправив всю структуру проекта. Я хочу попросить совета, как я могу применить подход MVVM в стиле android.arch.lifecycle для моего варианта использования.
Я не видел ничего более сложного, чем просто разделение Activity ViewModel между фрагментами. Но часто это не лекарство. enter image description here

То, что вы можете увидеть здесь - на самом деле беспорядок. Дело в том, что все делят ActivityViewModel. Соединения (агрегация) из FirstFragment означают, что ViewPager внутри FirstFragment инициирует ChildFragments и они также работают с тем же ActivityViewModel (убей меня). В результате все работают с одной общей моделью ViewModel.
Мое предложение состоит в том, чтобы добавить ViewModel для каждого слоя. Так что Activity/Fragments/ChildFragments имеют свои собственные ViewModels. Но что здесь появляется - как нам тогда общаться?
Возможные решения:

  • Наличие двух ViewModels для одного компонента. Один ViewModel будет обрабатывать/делегировать бизнес-логику, а другой - устанавливать связь. Две модели на компонент - не очень хорошо, да?
  • Имея старый интерфейс (пожалуйста, нет!)
  • Другие обходные пути - как слушатели изменений DB/SharedPrefs/Realm и шины событий (я слишком стар для этого :().

  • Ваше решение здесь!

Я скажу, что все вышеперечисленное нарушает многие принципы дизайна, так что мне делать? Как я должен выйти из этого беспорядка? Есть ли здесь Uncle Bob или другой superhero чтобы помочь?

PS - Ну, создание UML или других диаграмм - не моя сильная сторона. Простите за это.
PPS - мне известны образцы Google.

Ответ 1

Во-первых, нет никакого вреда в наличии нескольких ViewModel для одного Вид.

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

В вашем случае, если фрагменты и логика активности очень похожи, я думаю, вы можете пойти с одним ViewModel, но я бы этого избежал.

Что бы я сделал, это разбить активность ViewModel на более мелкие части и повторно использовать правильный ViewModel в моем Fragments, чтобы у меня не было God ViewModel, а не грубо тот же код в разных ViewModel.

Ответ 2

То, что я хотел бы предложить, вы можете обработать два ViewModel для всего вашего варианта использования.

Сделай одну ViewModel

Допустим, скажем, MyActivityViewModel для обработки всей логики, связанной с уровнем активности. Итак, если какая-либо фрагментная логика напрямую связана с вашей деятельностью, то поделитесь вашей ViewModel как ViewModel ниже:

ViewModelProviders.of(getActivity()).get(MyActivityViewModel.class); // Like this in fragment.

&

ViewModelProviders.of(this).get(MyActivityViewModel.class); // Like this in activity.

Это разделит общую ViewModel между вашей деятельностью и фрагментом.


Другая ViewModel будет использовать FirstFragment в вашем случае, если вам придется делиться логикой между ChildFragment:

Здесь вы можете поделиться ViewModel скажем, FragmentViewModel как FragmentViewModel ниже:

ViewModelProviders.of(this).get(FragmentViewModel.class); // Like this in FirstFragment which is having view pager.

&

ViewModelProviders.of(getParentFragment()).get(FragmentViewModel.class); // Like this in View pager fragments, getParentFragment() is First fragment in our case.

Хотя мы все еще можем использовать наш уровень активности MyActivityViewModel в наших дочерних фрагментах из FirstFragment, таких как:

ViewModelProviders.of(getActivity()).get(MyActivityViewModel.class);