Как стать автором
Обновить
6
0

Разработчик мобильных приложений

Отправить сообщение
Но я навскидку привёл реальную проблему, типичный юзкейс с навигацией opportunity, для которой хорошего решения не существует
Показывать что-либо на старте экрана — нормальная практика. В том числе и другой экран через directions. Можно использовать одни и те же фрагменты в разных графах, что увеличивает систематизацию. Почему данные подходы Вам не нравятся — для меня загадка.

Но количество дурацких решений в архитектуре Андроида по-прежнему велико.
Любому решению есть причина. Например, многие ругают Android за пересоздание активити при повороте и прочих сменах конфигурации. В то же время это — хорошая возможность смены лейаута и его поведения для конкретных условий. Вспомните тот же master-detail.

Моё мнение, что-то у них там в Андроидном подразделении Гугла фундаментально сломано.
Я часто присутствовал на презентациях о Jetpack и других решениях. Так же, на них присутствовали iOS-разработчики с большим опытом. В последний год от них всё чаще слышу возгласы вроде «почему у нас так нельзя» или «почему у нас такого нет». На мой взгляд, это о многом говорит.

Да, Android не идеален. Но не более, чем что-либо еще.

В то же время Вы ругаете Android и его практики и предлагаете не целевое использование Binder — технически опасное решение, которое снижает качество приложения на выходе.

Мне кажется, что проблема тут совсем не в Android…
Как-то не конструктивно с Вашей стороны.

Оно хорошее, но почему-то хромает
Ну это, на мой взгляд, точно лучше хаоса в навигации.

Спасибо вам большое за обсуждение!
Имелось в виду, что я не хочу тратить время на просмотр исходников Ваших проектов. А вводных данных, что Вы описали, возможно, недостаточно для подбора наиболее подходящего решения.
Это уже- вкусовщина. Вы не можете гарантировать, что в будущем к Account не добавятся дополнительные параметры. Так же, как и одинаковые наборы параметров для разных фрагментов. В этом случае обертка- более выгодное решение.
В случае Safe Args наличие обертки за один аргумент- небольшая плата за расширяемость и вариативность. И с type safe там тоже всё в порядке. Даже поддержка Null Safety есть.
Поймите правильно- здесь проблема не в наличии практик. Проблема в том, что Вы предлагаете использовать Binder для тех целей, для которых он не разрабатывался и не предназначен. Читайте про золотой молоток.
При этом Вы лишаете пользователя довольно ценного функционала- восстановления состояния.
Это механизм для удаленного вызова процедур, о чем написано в документации. Он не предназначен для хранения и передачи данных. Там же есть напоминание о смерти процесса.
OpportunitiesFragment не должен быть в стеке, при нажатии на Back должны возвращаться обратно на главный экран
Тогда сделайте главный экран частью графа и переходите оттуда- для Вас есть Nested navigation graphs.

OpportunitiesFragment не должен заниматься маршрутизацией, это вообще задача не View, а ViewModel
Я это и мел в виду- решение о переходе принимает ViewModel, но саму команду отдает View-слой. Navigation component предполагает использование view-driven архитектуры. Собственно, как и большинство рекомендуемых реализаций.

Как видите, решения есть. Я не вижу исходников Вашего проекта (да и не хочу тратить на это время), чтобы порекомендовать наиболее подходящее. Нужно уметь находить и правильно применять решения, а не сводить к несвязанному хаосу.
о возможностях, открывающихся, если отказываемся от восстановления состояния после рестарта процесса
UX важнее проблем разработки. За некоторыми исключениями. Нужно решать проблемы пользователей, а не собственные.

вроде бы ничего не утекает
Вы так можете случайно передать в долгоживущую часть приложения (или даже часть системы) сильную ссылку на объект с коротким жизненным циклом. Может даже и не один и не маленький в плане потребления памяти. Вот Вам и утечка.
С точки зрения описания в языке- разницы нет.
С точки зрения проектирования- сгенерированный args-класс инкапсулирует в себе набор параметров различных типов. Если (а точнее- когда) этот набор будет меняться со временем- содержать его внутри одного класса-обертки будет выгоднее.
Если Вам нужно, чтобы opportunities_fragment остался в стэке и пользователь мог на него вернуться- что мешает сразу в нем вызвать переход по нужному Вам destination? Например, в onActivityCreated() (предварительно обезопасив себя от повторения).
В остальном Вам сюда или сюда.
По поводу потенциала ) Обнаружил в закромах интерфейс, который делает любой класс Parcelable-ом.
Вы же понимаете, что такая реализация не переживет перезапуск?.. А, при неумелом использовании, еще и спровоцирует утечки.
Так же открывается история. На устройстве Android One версии 10. У Вас может быть либо другая версия приложения, либо баг прошивки вендора Вашего устройства.
Если гуглокодеры предлагают инструмент для решения некой задачи, то это не значит, что необходимо использовать именно этот инструмент. Особенно учитывая низкое качество создаваемых инструментов и вообще принимаемых решений (что касается Андроида).
Верно, не обязательно. Но есть рекомендуемые подходы. Это означает, что предлагаемый инструмент прошел UX-тестирование и имеет высокую степень совместимости с самим Android framework и сопутствующими инструментами.
Пример- Coroutines.

По поводу качества не согласен. Ранее была такая проблема, но новые инструменты радуют (если, конечно, Вы ознакомились с практиками их использования). Да, баги есть. Но их в среднем не больше, чем у других известных инструментов. Просто внимания больше, от того находят быстрее.

В итоге всё приходит к несвязанным fragment
Это говорит о непродуманности UX Вашего приложения. И об отношении к пользователям…
По опыту скажу, что при рефакторинге даже весьма хаотичных b2b-проектов, они, по итогу, прекрасно укладывались в навигационную диаграмму.

В Safe Args смысла не вижу
А он есть. Вы показали сторону вызова, а посмотрите на принимающую сторону:
class AaaFragment : Fragment() {
    private val args: AaaFragmentArgs by navArgs()
}
AaaFragmentArgs- это сгенерированный класс. В нем свойства, которые Вы укажете в navigation.xml (или в граф.редакторе). Не надо возиться с ключами и есть гарантия того, что Вы передадите в фрагмент то, что он ожидает. AaaFragmentArgs будет восстанавливаться при смене конфигурации и перезапуске. Минимальный набор для восстановления экрана с вводными.
В отдельных случаях Вам даже экшены использовать не обязательно.

как часто бывает в Андроиде, недоделанности и недопродуманности
Предполагаю, что Вы просто мало работали с другими ОС и фреймворками. Там разных недопониманий тоже хватает. Но, что в Android, что в других ОС, такие проблемы чаще возникают от незнания good practices.
Даже если так- хранить состояние в статике- плохая практика. Если не учитывать рестарт, то это будет работать так, как Вы ожидаете, только до тех пор, пока у Вас на одного наследника активити\фрагмента приходится один инстанс в стэке. Если инстансов несколько- начинаются проблемы. Например, когда пользователь из одного профиля соцсети через список друзей попадает в другой профиль.
ViewModel или аргументы\SavedInstanceState эти проблемы решают.
но в большинстве приложений это нецелесообразно
Это всегда и везде целесообразно. Если, конечно, Ваше приложение не состоит из одного экрана или вообще не имеет основного UI. Ну или если есть жесткие требования к безопасности.
Тот же навигатор- будет неприятно если ОС, по каким-либо веским причинам, решит выкинуть его из памяти. Например, во время достаточно долгого разговора.
YouTube проверил- перезапускает с сохранением, показал то же видео. Возможно, есть разница в версии ОС и приложений.
На моем наборе приложений те, что перезапускаются- в меньшинстве. И это всегда неприятно- на превью мультитаска видишь один контент, а после выбора- всё сначала.
Да, таких приложений просто много. Но это точно не норма и практиковать такой подход без веских причин не стоит.
Печально такое читать в 2020 году. При всём уважении, есть несколько замечаний
В большинстве приложений имеет смысл принять явное осознанное архитектурное решение, что в случае смерти процесса приложение просто перезапускается с нуля, не пытаясь восстанавливать состояние
Есть причины отказа от сохранения состояния, которые не зависят от самого разработчика. Они могут быть разными- использование сторонних кроссплатформенных движков, криво выстроенная логика сервиса\бэкенда\авторизации, прямое указание начальства\заказчика, куча легаси и прочее. Таких приложений совсем не большинство.

В ином случае, если решение было именно архитектурное (то есть архитектура является ограничителем для сохранения состояния)- то использованная Вами архитектура (или ее реализация) не удовлетворяет требованиям современных приложений. А это- Ваша личная проблема как разработчика.

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

Другой момент- насколько подробно сохранять состояние. Сегодня, как минимум, открыть тот же экран с теми же входными данными после перезапуска не составляет проблем.

Раньше можно было в любом месте воткнуть статическое поле и хранить в нём состояние
Это когда? Признаюсь честно- я мало писал под версии старше 2. Но уже 2.1 выкидывал процессы из памяти по причине нехватки, что, в последствии, приводило к перезапуску с, возможно, не пустым SavedInstanceState.

Такой подход имеет большой потенциал. Можно красиво обернуть и использовать во многих местах. Например, для передачи произвольных аргументов во фрагменты.
Простите, нет. Раз Вы в примерах используете Navigation component (или что-то очень на него похожее)- специально для этого придумали Safe Args. Это дополнение генерирует классы для аргументов фрагмента, которые, в свою очередь, сохраняются при смене конфигурации и перезапуске. Не факт, что Вам придется делать для этого много кастомных Parcelable\Serializable (в этом, кстати, тоже нет проблемы- студия для большинства типов генерирует реализацию Parcelable нажатием одной кнопки).

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

Если Вам нужно сохранять более подробное состояние и Вы эти данные обрабатываете во ViewModel- для Вас есть SavedStateHandle и AbstractSavedStateViewModelFactory.
Сложно сказать. Надо сравнивать конфигурации Ваших проектов и что в них происходит. Если даже дело не в самом Gradle- могу предположить, что какой-то плагин, который уже содержит asm, подключается раньше Вашего.

Быстрый гуглеж подсказывает, что это весьма вероятно. Например, вот так подключается asm в kotlin-android-extensions. И, судя по всему, по этой зависимости подключается версия asm с патчами для IntelliJ.

Я не уверен, но, возможно, это может стать решением и для Вас
Спасибо за статью. Тоже решал данную проблему лет 5 назад, но в рамках android и пользовался jarjar вручную. Сегодня, конечно, сама проблема уже не актуальна если говорить о android.
В Вашем случае другая ситуация, но по той же причине.
Я так и не смог выяснить точную причину, почему не получается зафорсить версию asm-а, хотя команда ./gradlew app:dependencies показывает, что версия заменилась на 7.2
То, с чем Вы столкнулись- перегрузка классов. Если Ваше приложение\плагин имеет классы, которые по именам и пакетам совпадают с теми, которые уже содержит рантайм (в Вашем случае- Gradle)- они не будут грузиться в память так как они там уже есть. Иными словами- конфликты классов решаются в сторону рантайма и, как итог, Ваш плагин обращается к классам Gradle, а не к классам Вашей библиотеки.

Зафорсить не получится потому, что байткод Gradle уже собран с зависимостью от asm 6 (по ссылке уже 7.1). Тут либо самому собирать Gradle из исходников c нужной зависимостью в надежде ничего не сломать, либо искать версию Gradle с asm 7.2 из коробки (если такая есть), либо пользоваться той версией asm, что поставляется с Gradle.

Ну или можно поступить так, как Вы- перепаковать либу или подвергнуть ее обфускации
Альтернативы- это всегда хорошо. А есть ли у этой библиотеки преимущества в сравнении с OkHttp? Он стал сейчас практически стандартом в разработке под Android. Например, если смотреть на создание запросов- я большой разницы не вижу
Это критично для любой системы сборки. Ведь весь процесс сборки упирается в произвольное чтение\запись, ресурсы CPU и насколько составляющие системы доработаны и оптимизированы
Заказчик несет риски на любом аккаунте. Только рисков больше он несет при публикации на аккаунте разработчика. Ведь если аккаунт разработчика забанят из-за приложения заказчика- виноват заказчик, так как всё делалось исключительно по его ТЗ и указаниям. Потому да, на такой случай надо сразу оговаривать неустойку в пользу разработчика
приложения, выполненные на заказ (бесплатные для пользователей) теперь неразумно разработчику (владельцу аккаунта Play Store) публиковать в своем аккаунте, предоставляя услугу (бесплатно, или за дополнительные деньги)
Вообще то так было всегда. Причем касательно любого маркета. И это нормально. Разработчик только реализует проект по ТЗ, дальнейшее его волновать не должно. Если заказчик хочет публиковаться в аккаунте разработчика- по этому поводу заключается дополнительное соглашение с условиями, которые устраивают обе стороны. Ведь, публикуя на своем аккаунте приложение заказчика, разработчик несет дополнительные риски.

А если Вы пишете свой проект- то Вы сам себе заказчик, а значит, несете риски обеих сторон.
выполнение требований Google теперь все больше зависит от заказчика приложения, от контента приложения, а не от разработчика
И так тоже было всегда. И это тоже правильно. Более того, если разработчик видит проблему с выполнением требований маркета- он должен поставить в известность заказчика, чтобы тот принял решения по устранению проблемы. В идеале на этапе рассмотрения ТЗ перед принятием в работу. Ведь хотелки заказчика, а не разработчика.
И получается, что теперь любой заказчик приложения, если думать головой заранее – обязан заводить себе аккаунт сам, заниматься его поддержкой, обновлением описаний приложений, скриншотов…
Конечно, ведь это не задачи разработки. Это задачи маркетинга, дизайна, копирайта, CEO и прочих смежных сфер. Если заказчик не в состоянии нанимать одного или нескольких людей с нужными навыками- значит он берет на себя риски, связанные с публикацией, и ему необходимо самому постигать навыки вышеперечисленных сфер.

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

С Вашей точки зрения разработчик и реализует, и следит за копирайтом, и продвигает приложение. А заказчик- абстрактное лицо, которое излагает идею, заплатит денег, снимает сливки с продукта и при этом не берет на себя никаких рисков. Тогда зачем в этой схеме заказчик? Ведь все риски несет разработчик.

Информация

В рейтинге
Не участвует
Откуда
Россия
Зарегистрирован
Активность