О канале
Привет! Меня зовут Алексей Панов и я занимаюсь Android разработкой с 2015 года, за это время я поработал над множеством проектов, несколько раз поменял стек технологий, успел пописать под iOS и опробовать Flutter. Сейчас сконцетрирован на мультиплатформенной разработке с помощью Kotlin Multiplatform.
Я люблю выступать на конференциях и рассказывать что-нибудь интересное про новые технологии, но не всегда хочется это делать в видео формате или же писать статьи, поэтому решил завести свой канал, где периодически буду делиться чем-то полезным про разработку на Kotlin и обо всем, что с этим языком так или иначе связано.
Здесь будут посты и про сам Kotlin, KMP, Compose, корутины и конечно же Android. В общем присоединяйтесь, будет интересно!
Привет! Меня зовут Алексей Панов и я занимаюсь Android разработкой с 2015 года, за это время я поработал над множеством проектов, несколько раз поменял стек технологий, успел пописать под iOS и опробовать Flutter. Сейчас сконцетрирован на мультиплатформенной разработке с помощью Kotlin Multiplatform.
Я люблю выступать на конференциях и рассказывать что-нибудь интересное про новые технологии, но не всегда хочется это делать в видео формате или же писать статьи, поэтому решил завести свой канал, где периодически буду делиться чем-то полезным про разработку на Kotlin и обо всем, что с этим языком так или иначе связано.
Здесь будут посты и про сам Kotlin, KMP, Compose, корутины и конечно же Android. В общем присоединяйтесь, будет интересно!
🔥16❤1
Сегодня буду проводить публичное собеседование на YouTube канале Android Broadcast. Мы будем проектировать мультиплатформееное приложение и обсуждать Kotlin Multiplatform, Coroutines, Compose. Это уже третье по счету (раз, два) публичное собеседование в котором я принимаю участие и так как корутины и compose мы обмусолили со всех сторон, сегодня больше сосредоточимся на KMP и на практических навыках написания мультиплатформенных приложений.
Начинаем прямой эфир в 19:00 по мск, так что залетайте на трансляцию.
После трансляции, пишите комменты под этим постом👇, если вы считаете, что что-то осталось не раскрытым или просто хотите предъявить мне за то, что я плохо провожу собесы, в общем не стесняйтесь)
Начинаем прямой эфир в 19:00 по мск, так что залетайте на трансляцию.
После трансляции, пишите комменты под этим постом👇, если вы считаете, что что-то осталось не раскрытым или просто хотите предъявить мне за то, что я плохо провожу собесы, в общем не стесняйтесь)
🔥15
Combine vs flatMapLatest + map
По горячим следам вчерашнего собеса, осталось недопонимание в чем разница между этими операторами.
Для решения задачки действительно можно было бы использовать оба решения, но есть ли разница?
В случае использования flatMapLatest за место combine:
👉 Будем каждый раз при изменении токена, пересоздавать счетчик. Это не критично, но если переставить местами два flow, то будем уже каждый раз ходить в БД, и это уже плохо
👉 Если за место flatMapLatest использовать любой другой flatMap*, то получим некорректное поведение, так так не отменим ticker flow
👉 Так как flatMapLatest отменяет корутину, важно, чтобы ticker поддерживал кооперативную отмену, иначе снова получим некорректное поведение
Чтобы запомнить все разнообразие операторов и как они работают, очень советую интерактивные marble диаграммы. Этот сайт про RxJs, но на самом деле разницы особо нет, если вам каких-то операторов не хватает во Flow, то можно воспользоваться библиотекой FlowExt
#Coroutines
По горячим следам вчерашнего собеса, осталось недопонимание в чем разница между этими операторами.
Для решения задачки действительно можно было бы использовать оба решения, но есть ли разница?
В случае использования 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
Это довольно распространенный вопрос и на сегодняшний день выбор либ просто огромен на любой вкус и цвет. Так что же выбрать? Конечно же
Есть еще решение Odyssey от Алексея Гладкова, но автор объявил о прекращении поддержки данной либы.
Таким образом настоятельно не рекомендую использовать официальное решение для навигации в любых более менее сложных приложениях. Можете посмотреть мой доклад, где я сравниваю эту либу и Decompose. Другие либы можно смело у себя использовать, но если вы проникнетесь подходом к навигации в Decompose, то можете посмотреть другой доклад, где уже разбираю как интегрироваться не только с Compose, но и SwiftUI.
Как вы поняли, я очень топлю за Decompose, хотя его сложность может многих отпугнуть, но стоит только проникнуться компонентым подходом и уже по-другому приложения писать не захочется!
#Compose #Navigation
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥33❤6👎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
Не так давно обновил проект до Gradle 8 и получил краш в релизной сборке
Как работает
Причем тут proguard
Когда запускается
Где может стрельнуть
Что за 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
Я выступал в роли программного комитета и помогал ребятам с прогонами. Все докладчики постарались на славу и определенно заслуживают ваш лайк
#Video #iOS #Android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16🔥9❤4
Декларативный Bottom Sheet
На мой взгляд, самый неудачный компонент в Compose из Material 2 — это Bottom Sheet. Он долгое время крашился при изменении конфигурации, его кучу раз переписывали, но все-равно на сегодняшний день он содержит много проблем:
😀 Приходится пилить костыли для работы с WindowInsets
😀 Он не прилипает к низу экрана
😀 Производительность оставляет желать лучшего
😀 Скрытие Scrim нельзя кастомизировать
А самое худшее — это его императивный API, в котором мы вынуждены управлять его показом через suspend функции show/hide, а также приходится оборачивать контент экрана в
😀 Решить проблему можно с помощью кастомной декларативной обертки
Как это работает
Показываем Bottom Sheet, если ассоциированный с ним стейт ≠ null, иначе скрываем
Особенности реализации
Нужно уметь показывать предыдущий контент, пока bottom sheet скрывается, несмотря на то, что данных уже нет
Нужно правильно вызывать лямбду
😀 Завязываться на
😀 Отслеживание изменения
Проблема😀
На текущий момент если скрыть Bottom Sheet через изменение стейта, то его скрытие можно перехватить жестом и тогда останемся в неконсистентном состоянии. Решить проблему можно либо скрытием Bottom Sheet без анимации, либо не занулять стейт, пока он не будет полностью скрыт.
😀 Гораздо лучше дела обстоят в Material 3, там из коробки Bottom Sheet уже декларативный и в нем было решено большинство проблем, только вот далеко не все используют M3 в своих проектах и, чтобы использовать его реализацию, придется копировать к себе кучу исходного кода, что тоже не круто. Таким образом если вы еще не перешли на компоузовский Bottom Sheet, то лучше пока и не торопиться😉
А как вы боретесь с проблемами с Bottom Sheet в своем проекте?
#Compose
На мой взгляд, самый неудачный компонент в Compose из Material 2 — это Bottom Sheet. Он долгое время крашился при изменении конфигурации, его кучу раз переписывали, но все-равно на сегодняшний день он содержит много проблем:
А самое худшее — это его императивный API, в котором мы вынуждены управлять его показом через suspend функции show/hide, а также приходится оборачивать контент экрана в
ModalBottomSheetLayout
. Это очень не удобно, когда нужно показать не статический контент, а полноценный экран с динамическим отображением данных и своей логикой. Как это работает
Показываем Bottom Sheet, если ассоциированный с ним стейт ≠ null, иначе скрываем
Особенности реализации
Нужно уметь показывать предыдущий контент, пока bottom sheet скрывается, несмотря на то, что данных уже нет
Нужно правильно вызывать лямбду
onDismiss
и здесь можно допустить ошибку:confirmValueChange
не вариант, так как теперь этот callback вызывается множество разsheetState.targetValue
также может привести к проблемам, так как targetValue
будет Hidden
даже если вы не до конца скрыли Bottom SheetПроблема
На текущий момент если скрыть Bottom Sheet через изменение стейта, то его скрытие можно перехватить жестом и тогда останемся в неконсистентном состоянии. Решить проблему можно либо скрытием 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. Пожалуйста, принимайте участие в розыгрыше только, если вы планируете смотреть конференцию, пусть билет достанется тому, кому он действительно нужен!
P.S. Пожалуйста, принимайте участие в розыгрыше только, если вы планируете смотреть конференцию, пусть билет достанется тому, кому он действительно нужен!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12
Розыгрыш билета на конференцию Mobius 2023 Autumn
Code coverage для UI тестов
⚙️ Тема анализа покрытия кода Unit тестами уже не нова, для Java уже давным-давно существует библиотека JaCoCo, для Kotlin есть официальный Gradle Plugin Kover. Оба этих инструмента позволяют анализировать ваш код и генерировать различные отчеты о его покрытии Unit тестами. Это безусловно полезные инструменты для улучшения качества вашего кода и уверенности в нем.
⚙️ Но как обстоят дела с UI тестами? Можем ли мы с помощью них проанализировать процент покрытия тестами нашей бизнес логики?
⚙️ На этот вопрос ответил мой коллега из Контура, Игорь Гордеев, в своей статье на Хабре. Он рассказал, как с помощью библиотеки VisualFSM, конечных автоматов и щепотки кодогенерации сделать такое покрытие и упростить жизнь и тестировщикам, и разработчикам в тысячу раз!
Приятного чтения🤯
#Android #Testing
Приятного чтения
#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.
Так что приходите посоревноваться друг с другом, а тот кто наберёт больше всего баллов, получит хороший приз🏅
Мы подготовили аж 40
Так что приходите посоревноваться друг с другом, а тот кто наберёт больше всего баллов, получит хороший приз
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8❤1
VPN, который не заблокируют
🌐 Ни для кого не секрет, что сейчас все больше протоколов VPN подвергается блокировке — это и WireGuard, и OpenVPN, и другие, но решение есть!
Причём собрать свое мобильное приложение с VPN, которое не боится блокировок достаточно легко. Для этого нам потребуется связка WireGuard + xRay.
Принцип работы
😀 xRay — это прокси-сервер, который умеет маскировать трафик под браузерный (TLS). Нам лишь нужно запустить VPN туннель и весь трафик пропускать через него.
Пример на Android
😀 Запускаем xRay с переданной конфигурацией. В
😀 Подготавливаем VpnService, чтобы ваше приложение могло создавать VPN туннель.
😀 Поднимаем VPN туннель. Внутри конфига в Endpoint указываем localhost, чтобы весь трафик шел в xRay.
Как видим реализовать свое приложение для VPN с данными либами довольно не сложно🤔 . И так как эти либы написаны на Go, мы их можем запустить где угодно, будь то Android, iOS или любая другая платформа.
Если у вас остались вопросы и тема заинтересовала, то пишите комменты, попробую помочь, чем смогу👇
Причём собрать свое мобильное приложение с VPN, которое не боится блокировок достаточно легко. Для этого нам потребуется связка WireGuard + xRay.
Принцип работы
Пример на Android
inbounds
указываем входящий трафик от WireGuard с localhost и протоколом dokodemo-door
, а в outbounds
исходящий трафик на ваш сервер, тут можно использовать либо облегченный протокол vless
, либо полноценный протокол с шифрованием vmess
.
LibXray.runXray("", configFile.absolutePath, 0)
GoBackend.VpnService.prepare(context)
val backend = GoBackend(applicationContext)
val tunnel: Tunnel = WireGuardTunnel() // Ваш класс, реализующий интерфейс Tunnel
val config: Config = ... // Ваш конфиг для WireGuard
backend.setState(tunnel, Tunnel.State.UP, config) // Обязательно вызывать с фонового потока
Как видим реализовать свое приложение для VPN с данными либами довольно не сложно
Если у вас остались вопросы и тема заинтересовала, то пишите комменты, попробую помочь, чем смогу👇
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥14👍1🤔1
Если вы находитесь на площадке Мобиуса, то всех буду ждать в первом зале или приходите посмотреть доклад онлайн, если есть такая возможность.
До встречи
Please open Telegram to view this post
VIEW IN TELEGRAM
🤝5🔥4👍3