Warning: Undefined array key 0 in /var/www/tgoop/function.php on line 65

Warning: Trying to access array offset on value of type null in /var/www/tgoop/function.php on line 65
3 - Telegram Web
Telegram Web
Сегодня буду проводить публичное собеседование на YouTube канале Android Broadcast. Мы будем проектировать мультиплатформееное приложение и обсуждать Kotlin Multiplatform, Coroutines, Compose. Это уже третье по счету (раз, два) публичное собеседование в котором я принимаю участие и так как корутины и compose мы обмусолили со всех сторон, сегодня больше сосредоточимся на KMP и на практических навыках написания мультиплатформенных приложений.

Начинаем прямой эфир в 19:00 по мск, так что залетайте на трансляцию.

После трансляции, пишите комменты под этим постом👇, если вы считаете, что что-то осталось не раскрытым или просто хотите предъявить мне за то, что я плохо провожу собесы, в общем не стесняйтесь)
🔥15
Combine vs flatMapLatest + map

По горячим следам вчерашнего собеса, осталось недопонимание в чем разница между этими операторами.
Для решения задачки действительно можно было бы использовать оба решения, но есть ли разница?

В случае использования flatMapLatest за место combine:
👉 Будем каждый раз при изменении токена, пересоздавать счетчик. Это не критично, но если переставить местами два flow, то будем уже каждый раз ходить в БД, и это уже плохо
👉 Если за место flatMapLatest использовать любой другой flatMap*, то получим некорректное поведение, так так не отменим ticker flow
👉 Так как flatMapLatest отменяет корутину, важно, чтобы ticker поддерживал кооперативную отмену, иначе снова получим некорректное поведение

Чтобы запомнить все разнообразие операторов и как они работают, очень советую интерактивные marble диаграммы. Этот сайт про RxJs, но на самом деле разницы особо нет, если вам каких-то операторов не хватает во Flow, то можно воспользоваться библиотекой FlowExt

#Coroutines
🔥13👍3😱1
Какой оператор во Flow представлен на marble диаграмме ниже?
Anonymous Quiz
4%
flatMapLatest
19%
combine
52%
zip
24%
flatMapMerge
👍6😢1
Что выбрать для навигации в Compose🤨

Это довольно распространенный вопрос и на сегодняшний день выбор либ просто огромен на любой вкус и цвет. Так что же выбрать? Конечно же Decompose решать вам на основе требований к навигации в вашем приложении.

🤖 Jetpack Compose Navigation — официальная библиотека
👍 Поддержка от Google, интеграция с ViewModel
👎Только для Android и еще миллион минусов

🤖 Jetpack Compose Destinations — обертка над официальной либой
👍 Решает некоторые проблемы первой либы
👎 Добавляет новых проблем из-за кодогенерации и зависимости на accompanist либы

🤖 Modo — либа от создателя Cicerone, Константина Цховребова
👍 Строится на принципах UDF, очень простая
👎 Только для Android, еще не в релизе, маленькое коммьюнити

👩‍💻 Appyx — решение для навигации от Bumble
👍 Декларативный подход, классные анимации из коробки, поддержка KMP
👎 Только для Compose, довольно сложная, небольшое коммьюнити

👩‍💻 Voyager — популярная и простая либа для навигации
👍 Много интеграций с привычными инструментами, легкая в использовании, поддержка KMP
👎 Только для Compose, есть проблемы со стабильностью

🌳 Decompose — либа от Аркадия Иванова, автора MVIKotlin
👍 Единственное решение не завязанное на UI фреймворк, декларативный подход, огромная гибкость, высокая стабильность
👎 Высокий порог входа, приходится писать много кода

Есть еще решение Odyssey от Алексея Гладкова, но автор объявил о прекращении поддержки данной либы.

Таким образом настоятельно не рекомендую использовать официальное решение для навигации в любых более менее сложных приложениях. Можете посмотреть мой доклад, где я сравниваю эту либу и Decompose. Другие либы можно смело у себя использовать, но если вы проникнетесь подходом к навигации в Decompose, то можете посмотреть другой доклад, где уже разбираю как интегрироваться не только с Compose, но и SwiftUI.

Как вы поняли, я очень топлю за Decompose, хотя его сложность может многих отпугнуть, но стоит только проникнуться компонентым подходом и уже по-другому приложения писать не захочется!

#Compose #Navigation
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥336👎1
R8 full mode

Не так давно обновил проект до Gradle 8 и получил краш в релизной сборке⚪️. Все из-за включенного по умолчанию R8 full mode. Прежде чем разберемся, что поменялось, давайте для начала вспомним, кто такой этот ваш R8.

☢️ R8 — это утилита для удаления лишнего кода, его минификации и оптимизации

Как работает
⚙️ Строит граф от рутов, помеченных -keep в правилах proguard, и удаляет все до чего не смог дотянуться

Причем тут proguard
⚙️ Ранее в Android использовался аналог R8 под названием ProGuard, правила остались для совместимости

Когда запускается
⚙️ Во время сборки с включенным флагом isMinifyEnabled

Где может стрельнуть
⚙️ При использовании рефлексии или JNI

Что за full mode
⚙️ Включает более агрессивный режим и вырезает еще больше кода. Например, классы, создаваемые только через рефлексию, должны явно помечаться через -keep правило. Также R8 удаляет сигнатуру дженериков, что стрельнуло у меня в связке Retrofit + RxJava2

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

📌 Подробнее почитать про R8 full mode и известные проблемы можно тут, но эти правила мне не помогли, поэтому в комментах напишу, что помогло.
Также если хотите глубже погрузиться в правила ProGuard, то рекомендую официальный мануал и андроидовскую доку.

Столкнулись ли вы с подобной проблемой на своем проекте

#Android #R8 #ProGuard
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16
Этим летом проводили MobileUpdate в Екатеринбуржском офисе Контура☁️, где было 5 крутых докладов по мобильной разработке. А теперь все записи докладов стали доступны на YouTube🟥

🤖 Влада Шамшукаева рассказала как работать с графикой в Compose, а также о том как одну и ту же задачу можно решать совершенно разными способами

🍏 Алексей Агапов набросил, что классы и паттерны проектирования вам больше не нужны, достаточно лишь функции и знания о Functional Core / Imperative Shell.

🤖 Игорь Гордеев поведал о том как уменьшать шаблонный код с помощью KSP на примере библиотеки VisualFSM

🍏 Анастасия Чупова поделилась довольно забавной историей о фейлах при работе с диплинками в SwiftUI

🤖 И наконец Евгений Мельцайкин рассказал про плагины в Gradle, как с помощью них сократить код в ваших gradle файлах и как при этом не выстрелить себе в ногу.

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

P.S. Уровень монтажа и картинки просто мое почтение

#Video #iOS #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥94
Декларативный Bottom Sheet

На мой взгляд, самый неудачный компонент в Compose из Material 2 — это Bottom Sheet. Он долгое время крашился при изменении конфигурации, его кучу раз переписывали, но все-равно на сегодняшний день он содержит много проблем:
😀 Приходится пилить костыли для работы с WindowInsets
😀 Он не прилипает к низу экрана
😀 Производительность оставляет желать лучшего
😀 Скрытие Scrim нельзя кастомизировать

А самое худшее — это его императивный API, в котором мы вынуждены управлять его показом через suspend функции show/hide, а также приходится оборачивать контент экрана в ModalBottomSheetLayout. Это очень не удобно, когда нужно показать не статический контент, а полноценный экран с динамическим отображением данных и своей логикой.

😀Решить проблему можно с помощью кастомной декларативной обертки

Как это работает
Показываем Bottom Sheet, если ассоциированный с ним стейт ≠ null, иначе скрываем

Особенности реализации
Нужно уметь показывать предыдущий контент, пока bottom sheet скрывается, несмотря на то, что данных уже нет
Нужно правильно вызывать лямбду onDismiss и здесь можно допустить ошибку:
😀 Завязываться на confirmValueChange не вариант, так как теперь этот callback вызывается множество раз
😀 Отслеживание изменения sheetState.targetValue также может привести к проблемам, так как targetValue будет Hidden даже если вы не до конца скрыли Bottom Sheet

Проблема😀
На текущий момент если скрыть Bottom Sheet через изменение стейта, то его скрытие можно перехватить жестом и тогда останемся в неконсистентном состоянии. Решить проблему можно либо скрытием Bottom Sheet без анимации, либо не занулять стейт, пока он не будет полностью скрыт.

😀 Гораздо лучше дела обстоят в Material 3, там из коробки Bottom Sheet уже декларативный и в нем было решено большинство проблем, только вот далеко не все используют M3 в своих проектах и, чтобы использовать его реализацию, придется копировать к себе кучу исходного кода, что тоже не круто. Таким образом если вы еще не перешли на компоузовский Bottom Sheet, то лучше пока и не торопиться😉

А как вы боретесь с проблемами с Bottom Sheet в своем проекте?

#Compose
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12
На ближайшей конференции Mobius я буду участвовать сразу в двух сессиях:

🗓 2 ноября мы вместе с Дмитрием Григорьевым проведем крутую игру-квиз по Jetpack Compose в онлайн формате, где осветим большое количество самых разных и интересных тем из мира Compose, а участники смогут посоревноваться друг с другом за классные призы.

🗓 10 ноября уже оффлайн в Санкт-Петербурге буду рассказывать про подкапотную магию работы стейта в Compose, рассмотрим почему он далеко не так прост, как кажется на первый взгляд и почему он является важнейшим механизмом в работе всего Compose.

🎁 В связи с этим хочу устроить аттракцион невиданной щедрости провести розыгрыш билета на ближайшую конференцию Mobius. Из обязательных условий — быть подписанным на telegram канал @kotlin_adept, а также буду очень благодарен, если поделитесь ссылкой на данный канал со своими коллегами. Ведь, чем больше аудитория, тем больше мотивации чаще постить качественный контент🙂

❗️Для участия в розыгрыше достаточно нажать на кнопку «Принять участие» под следующим постом и мы определим победителя через 24 часа.

P.S. Пожалуйста, принимайте участие в розыгрыше только, если вы планируете смотреть конференцию, пусть билет достанется тому, кому он действительно нужен!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12
Розыгрыш билета на конференцию Mobius 2023 Autumn
Kotlin Adept Notes
Розыгрыш билета на конференцию Mobius 2023 Autumn
Результаты розыгрыша:

Победитель:
1. Danil

Проверить результаты
👏111👍1🎉1
Code coverage для UI тестов

⚙️ Тема анализа покрытия кода Unit тестами уже не нова, для Java уже давным-давно существует библиотека JaCoCo, для Kotlin есть официальный Gradle Plugin Kover. Оба этих инструмента позволяют анализировать ваш код и генерировать различные отчеты о его покрытии Unit тестами. Это безусловно полезные инструменты для улучшения качества вашего кода и уверенности в нем.

⚙️ Но как обстоят дела с UI тестами? Можем ли мы с помощью них проанализировать процент покрытия тестами нашей бизнес логики?

⚙️На этот вопрос ответил мой коллега из Контура, Игорь Гордеев, в своей статье на Хабре. Он рассказал, как с помощью библиотеки VisualFSM, конечных автоматов и щепотки кодогенерации сделать такое покрытие и упростить жизнь и тестировщикам, и разработчикам в тысячу раз!

Приятного чтения 🤯

#Android #Testing
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11👍3
Compose Quiz

🔴Ребят, напоминаю, что сегодня пройдет квиз по Jetpack Compose в 12:15 (мск) на сайте Mobius. И принять участие вы можете абсолютно бесплатно так как это Community Day, достаточно просто зарегистрироваться по ссылке.

Мы подготовили аж 40 😱 вопросов по Compose и осветили все самые значимые темы, знание которых определенно поможет вам в повседневной разработке на Compose.

Так что приходите посоревноваться друг с другом, а тот кто наберёт больше всего баллов, получит хороший приз🏅
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥81
VPN, который не заблокируют

🌐Ни для кого не секрет, что сейчас все больше протоколов VPN подвергается блокировке — это и WireGuard, и OpenVPN, и другие, но решение есть!
Причём собрать свое мобильное приложение с VPN, которое не боится блокировок достаточно легко. Для этого нам потребуется связка WireGuard + xRay.

Принцип работы

😀xRay — это прокси-сервер, который умеет маскировать трафик под браузерный (TLS). Нам лишь нужно запустить VPN туннель и весь трафик пропускать через него.

Пример на Android

😀Запускаем xRay с переданной конфигурацией. В inbounds указываем входящий трафик от WireGuard с localhost и протоколом dokodemo-door, а в outbounds исходящий трафик на ваш сервер, тут можно использовать либо облегченный протокол vless, либо полноценный протокол с шифрованием vmess.

LibXray.runXray("", configFile.absolutePath, 0)


😀Подготавливаем VpnService, чтобы ваше приложение могло создавать VPN туннель.

GoBackend.VpnService.prepare(context)


😀Поднимаем VPN туннель. Внутри конфига в Endpoint указываем localhost, чтобы весь трафик шел в xRay.

val backend = GoBackend(applicationContext)
val tunnel: Tunnel = WireGuardTunnel() // Ваш класс, реализующий интерфейс Tunnel
val config: Config = ... // Ваш конфиг для WireGuard
backend.setState(tunnel, Tunnel.State.UP, config) // Обязательно вызывать с фонового потока

Как видим реализовать свое приложение для VPN с данными либами довольно не сложно 🤔. И так как эти либы написаны на Go, мы их можем запустить где угодно, будь то Android, iOS или любая другая платформа.

Если у вас остались вопросы и тема заинтересовала, то пишите комменты, попробую помочь, чем смогу👇
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍1🤔1
⚪️Ребят, напомню, что сегодня на Мобиус в 16:00 мск будет мой доклад про подкапотную магию стейта в Compose. Там будет много всего интересного, а именно:

🟢Поговорим про устройство снапшотов и узнаем причем здесь базы данных
🔵Разберемся как сделать свой стейт
🟣Рассмотрим как происходит чтение и запись, как снапшоты изолируются друг от друга
🔵А также ответим на вопрос, как при изменении стейта происходит рекомпозиция функций

Если вы находитесь на площадке Мобиуса, то всех буду ждать в первом зале или приходите посмотреть доклад онлайн, если есть такая возможность.

До встречи❤️
Please open Telegram to view this post
VIEW IN TELEGRAM
🤝5🔥4👍3
Compose Snapshots

После доклада меня много спрашивали, а зачем мне вообще знать про снапшоты? Где эти знания применить на практике?

💡 И на мой взгляд, в первую очередь их нужно знать, чтобы разобраться, а каким образом изменение State внутри Composable функции приводит к рекомпозиции?

✳️Давайте сначала вспомним, что вообще такое Snapshot

Это механизм, используемый внутри Compose State и не только, для работы с множественными изолированными копиями состояния. Снапшоты также позволяют сделать безопасное изменение стейта конкурентно без блокировок. Можете думать про снапшоты как про транзакции в базах данных или как про ветки в git.

✳️Причем тут снапшоты и рекомпозиция?

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


private inline fun <T> composing(
composition: ControlledComposition,
modifiedValues: IdentityArraySet<Any>?,
block: () -> T
): T {
val snapshot = Snapshot.takeMutableSnapshot(
readObserverOf(composition), writeObserverOf(composition, modifiedValues)
)
try {
return snapshot.enter(block)
} finally {
applyAndCheck(snapshot)
}
}


✳️Где снапшоты могут пригодиться на практике?

🟠Если вдруг вы захотите написать свою либу поверх compose runtime
🟡Для безопасного изменения стейта с нескольких потоков
🔵Для создания своего изменяемого Stable типа, отслеживаемого Compose
🔵Для всего, на что способно ваше воображение! Например, почему бы не работать с БД через Compose State? Что? Да! Это тоже возможно благодаря снапшотам.

Но самое крутое и полезное применение снапшотов я покажу в следующем посте, так что stay tuned 💻

#Compose #Snapshots
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥9
This media is not supported in your browser
VIEW IN TELEGRAM
Compose withAnimation

В SwiftUI есть очень классная фича withAnimation, позволяющая сделать анимацию вьюшки просто путем изменения состояния, а сама анимация произойдет как по волшебству.


@State private var showDetail = false

var body: some View {
VStack {
Button("Show details") {
withAnimation {
showDetail.toggle()
}
}

if showDetail {
Text("Details")
}
}
}


Не справедливо, что такого механизма нет из коробки в Compose, и инженер из Google решил исправить это недоразумение. Он сделал свой аналог withAnimation и реализовал это с помощью Snapshot API, про который мы говорили ранее.

Как это работает?

1. Создается пустой словарь состояний для анимации
2. Выполняется лямбда блок внутри Snapshot, в этой лямбде могут происходить изменения стейта
3. У Snapshot вызывается writeObserver при каждой записи в State и заполняется информация для анимации
4. Данные мапятся в другой тип, откуда достаются измененные значения
5. Уничтожается Snapshot, чтобы не допустить утечек памяти, при этом изменения не применяются глобально! «Все что произошло в снапшоте, остается в снапшоте»©
6. Анимируются значения


internal suspend fun withAnimation(
adapterRegistry: StateObjectAdapterRegistry,
animationSpec: AnimationSpec<Any?>,
block: () -> Unit
) {
val statesToAnimate = mutableMapOf<Any, StateObjectAdapter>() // 1
val snapshot = Snapshot.takeMutableSnapshot(
writeObserver = { changedState ->
statesToAnimate[changedState] = checkNotNull(adapterRegistry.getAdapterFor(changedState)) // 3
}
)
val targetValues = snapshot.enter {
block() // 2
buildTargetValues(statesToAnimate) // 4
}
snapshot.dispose() // 5

animateValues(targetValues, animationSpec) // 6
}


Если у вас есть еще идеи как можно применить снапшоты, делитесь своими мыслями в комментариях👇

#Compose #Snapshots #Animations
🔥10👍2
Сегодня на конференции YaTalks будет очень крутая сессия, на которой я (Алексей Панов) и Алексей Гладков будем стараться максимально закопать Flutter и возвысить KMP, другая же команда, состоящая из Геннадия Евстратова и Евгения Сатурова, будут пытаться нам противостоять.

Все это будет проходить в формате настоящих дебатов!

Так что регистрируйтесь и приходите посмотреть прямой эфир в 19:00 (мск). Заруба должна получиться просто огненной 🔥

А если вы хотите внести свой вклад в победе над Flutter, то пишите какие бы вы задали самые неудобные вопросы команде Flutter в комментариях и возможно мы возьмем их в эфир.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11❤‍🔥11
По мотивам прошедших дебатов хотелось бы обсудить плюсы и минусы Flutter в сравнении с KMP и Compose Multiplatform для разработки мобильных приложений.

👍Плюсы Flutter

▫️Высокопроизводительный графический движок Impeller
▫️Очень простой порог входа
▫️Куча готовых плагинов
▫️На сегодняшний день гораздо популярнее KMP
▫️В релизе с 2018 года, в отличие от вышедшего в этом году в релиз KMP и тем более Compose MP for iOS, который все ещё в альфе
▫️Flutter на iOS работает быстрее и стабильнее, чем Compose для iOS на сегодняшний день
▫️Есть киллер фичи Hot Reload / Hot Restart ускоряющие разработку
▫️На Flutter можно официально разрабатывать под Аврору и Фуксию (зачем — это уже другой вопрос)

👎Минусы Flutter

🔸Очень больно переводить существующий проект на Flutter, с KMP это можно делать просто и постепенно
🔸Dart по сравнению с Kotlin выглядит очень устаревшим, приходится писать гораздо больше кода
🔸Многопоточность в Dart с изолятами довольно ограничена по сравнению с возможностями и гибкостью корутин в Kotlin
🔸Верстка одного и того же экрана на Flutter получается примерно в 2 раза больше чем на Compose
🔸Более примитивная система сборки по сравнению с Gradle
🔸Кодогенерацию нельзя органично встроить в процесс сборки, про компиляторные плагины даже речи не идёт
🔸Нетипобезопасные платформенные каналы, все креши будут в рантайме, если где-то ошибётесь (но есть альтернатива в виде Pigeon)
🔸Множество публичных плагинов спорного качества
🔸Нет официального решения для организации многомодульного проекта (есть только инструмент Melos)
🔸Dart используется только во Flutter, в отличие от Kotlin, который используется в различных областях

Это все моменты, что я смог вспомнить, если у вас есть что добавить, то не стесняйтесь писать свои мысли в комментариях ⌨️

#Flutter #KMP
Please open Telegram to view this post
VIEW IN TELEGRAM
👍151
Forwarded from Compose Broadcast (Alex Panov)
This media is not supported in your browser
VIEW IN TELEGRAM
Автор крутого доклада про компиляторные плагины для Compose с предыдущего Mobius опубликовал исходники плагинов на GitHub.

Там очень много всего интересного и полезного:
👉 Анализ стабильности параметров Composable функции
👉 Подсветка рекомпозиций в UI
👉 Автоматическая генерация и удаление testTag
👉 Логирование причин рекомпозиции и другое

Эти плагины наконец-то решают извечную проблему анализа лишних рекомпозиций и оптимизаций вашего кода в Compose, теперь делать высокопроизводительные приложения стало гораздо проще!

#compose #plugins
👍12👏3
2025/07/09 04:57:44
Back to Top
HTML Embed Code: