Комментарии 19
Я бы не стал говорить, что всё прям ужасно. Если у вас на одном экране пара фрагментов и нужно взаимодействие, и именно эта комбинация этих фрагментов только один раз встречается в приложении, то зачем придумывать себе проблему и потом же решать её? Я понимаю, что это может ухудшать переиспользуемость, но что если она и не нужна в конкретном месте..
Размазывать синглтон типа отто по всему приложению, потом оттираться замучаетесь.
Для 2 отдельных компонентов то сервис с подпиской и лучше, это их личная зависимость.
Каждый знает, что вот зависит от такого сервиса, вполне тестируемо, подменяемо.
Но и предложенный Вами сервис Shared ViewModel полностью не заменяет. Это уже отдаленно напоминает redux или mvi.
Остальное тоже не идеально. Опишу подробнее:
Мы строим ViewModel для конкретной View.Не обязательно. В идеале ViewModel не должна знать о View, которая ее использует. Так мы разделяем логику (ViewModel) и механику (View) работы презентационного слоя. Таким образом, можно переиспользовать ViewModel на нескольких экранах схожего назначения. Например, можно использовать один и тот же тип ViewModel как в мобильной версии, так и в версии для Android TV.
Мы не можем просто взять такой фрагмент и добавить в ViewPager, напримерИ не нужно. Этим и распределением параметров должен заниматься наследник FragmentStateAdapter (или FragmentStatePagerAdapter). В идеале, по мере пролистывания, фрагменты должны создаваться и уничтожаться чтобы не мусорить в памяти. Решение этого вопроса сложнее, чем «просто добавить», и аргументы вполне подходят как часть решения.
вы создали фрагмент с параметрами, работаете в нем, данные поменялись, фрагмент уже показывает что-то другое.Очевидно, в этой ситуации лучше показать другой фрагмент. А предыдущий сохраняется в стэке по желанию.
ViewModel запрашивает параметры у сервиса по типу класса параметров.И это порождает проблемы с уникальностью. Если у Вас в стэке несколько экземпляров одного и того-же фрагмента или фрагментов, которые используют один и тот-же тип параметров — после восстановления стейта Вы можете получить стопку одинаковых экранов.
Пример — экран профиля пользователя с параметром userId. Вы смотрите на профиль 3, в который попали из друзей профиля 2, в который попали так же из профиля 1. И в любой момент хотите вернуться к предыдущему. Да, в случае сервиса это решаемо, но в аргументах это всё уже решено.
Если объем передаваемых данных свыше 500 кб., то приложение может аварийно завершитьсяПотому не стоит хранить в аргументах и saved state контент. Здесь надо хранить только параметры, и, в этом случае, лимит исчерпать довольно сложно.
Простите за большое количество текста. В паре строк эти вещи не опишешь.
Простите за большое количество текста.
Отличная дискуссия, спасибо!
Не обязательно. В идеале ViewModel не должна знать о View, которая ее использует. Так мы разделяем логику (ViewModel) и механику (View) работы презентационного слоя. Таким образом, можно переиспользовать ViewModel на нескольких экранах схожего назначения. Например, можно использовать один и тот же тип ViewModel как в мобильной версии, так и в версии для Android TV.
ViewModel ничего и не знает о View. ViewModel лишь содержит ниточки, через которые она взаимодействует с View. Механика View может быть любой. У нас в проекте ViewModel отлично работает в мобильной версии и АТВ. В некоторых случаях реализация сервисов общая, в некоторых — у каждого своя (DI).
И не нужно. Этим и распределением параметров должен заниматься наследник FragmentStateAdapter (или FragmentStatePagerAdapter).
Предпочитаю логику отделять от Android. Задача FragmentStatePagerAdapter лишь дать нужный фрагмент по требованию пользователя. А что этот фрагмент отобразит, известно логике.
И это порождает проблемы с уникальностью.
Такие же проблемы могут быть и у Safty args. После восстановления state параметры и не нужны, все уже живет во ViewModel. А если есть цепочки, как с примером о профилях, то эту breadcrumb логику я бы тоже перенес в сервис. Это немного сложнее, конечно.
Потому не стоит хранить в аргументах и saved state контент.
Безусловно! Но бывает соблазн быстренько что-то показать, например, в диалоге через Navigation Component.
В качестве резюме могу сказать, что я пытаюсь максимально абстрагироваться от Android, делая акцент на логике. Это помогает в тестировании и переходу к новым инструментам. Например, переход на Navigation Component получился почти безболезненным. Возможно, это также поможет мне, когда мы захотим попробовать Kotlin multiplatform.
Добрый день, почти получилось, только смерть процесса приложения забили учитывать.
Предпочитаю логику отделять от Android.В данном конкретном случае адаптер, скорее, часть механики View. А вот дочерние фрагменты уже подключены к логике. В этом кейсе как раз и выгодно использовать Shared ViewModel — родительский фрагмент ее порождает, дочерние (из ViewPager) подключаются. При этом ничто Вам не мешает в дочерних порождать собственные ViewModel для, например, поставки данных.
Так или иначе, всю логику за пределы Android Вы не сможете вынести, как бы Вам не хотелось.
Такие же проблемы могут быть и у Safty argsНе могу представить себе такого кейса. Safe Args — просто обертка над аргументами. А один инстанс аргументов приходится на один инстанс фрагмента.
то эту breadcrumb логику я бы тоже перенес в сервисКак говорится, «у любой задачи есть минимум 3 решения». Можно и по-Вашему, а можно взять готовое решение — Navigation Component + Safe Args, что обойдется дешевле во всех смыслах.
что я пытаюсь максимально абстрагироваться от Android, делая акцент на логике. Это помогает в тестировании и переходу к новым инструментам.Ну вот для этого пакеты AndroidX поставляются с зависимостями для тестирования. Navigation Component не исключение.
Много особенностей операционной системы проигнорировано, и это вызовет много проблем в будущем. Несколько раз пытался нечто похожее на идеи автора, но всегда когда учитывал множество мелких моментов, получалось очень сложно в итоге. Проще было смириться и использовать средства андроид фреймворка.
Решит ли это проблему?
Такую штуку и не видел даже, в альфе ещё, вроде. Функционала недостаточно пока ещё, можно только передать результат, чем-то напоминает onActivityResult. Вот интересно, зачем в Гугл такую штуку добавили, ведь здесь тоже можно использовать SharedViewModel… Возможно, там тоже понимают проблему, и вскоре мы увидим новый arch component. Хорошо бы...
Несколько категоричное мнение, если честно. Фрагменты — это необязательно разные экраны в приложении. Если несколько фрагментов не представляют собой автономные единицы, то вполне можно сделать одну ViewModel. Да и сама она не должна знать о том, один там фрагмент или несколько. Это особенности отображения, которые еще и могут отличаться от устройства к устройству, в зависимости от конфигурации.
Почему я не использую SharedViewModel для фрагментов?