Буду сейчас принимать участие в стриме от Яндекса на Mobius, будем фиксить баги в прямом эфире.
Подключайтесь✅
Подключайтесь
Please open Telegram to view this post
VIEW IN TELEGRAM
Как ускорить релизную сборку
Из всех докладов на Mobius, которые мне удалось посмотреть, могу выделить классный доклад о том, как в Т-Банке случайно ускорили релизную сборку в два раза.
Я думаю, у многих в проектах работа R8 занимает больше всего времени из всего процесса сборки, а в крупных проектах выполнение этой таски может доходить до 3 часов🙀 — и это требует огромного количества оперативной памяти.
Так что же может значительно увеличивать длительность выполнения этой таски?
1. Неоптимальные правила
Обычно это правила с условием, например, такие встречаются в библиотеке kotlinx-serialization. На них тратится больше всего времени, нужно быть аккуратнее с такими правилами и не дублировать их в своём коде, так как правила для R8 уже поставляются вместе с библиотеками.
2. Огромное количество ресурсов
Таска shrinkResources может потреблять очень много оперативной памяти, и если в вашей дизайн-системе вы предоставляете большую библиотеку иконок, то, возможно, стоит пересмотреть подход и не тащить тысячи иконок, чтобы потом R8 не удалял их очень долго. Как вариант, можно рассмотреть загрузку иконок с CDN по запросу.
А главная проблема в том, что добавление любой библиотеки в проект или изменение правил в одном из модулей может сказаться на времени сборки всего проекта, поэтому нужно не забивать на мониторинг времени сборки приложения и вовремя реагировать на изменения.
#R8 #Gradle
Из всех докладов на Mobius, которые мне удалось посмотреть, могу выделить классный доклад о том, как в Т-Банке случайно ускорили релизную сборку в два раза.
Я думаю, у многих в проектах работа R8 занимает больше всего времени из всего процесса сборки, а в крупных проектах выполнение этой таски может доходить до 3 часов
Так что же может значительно увеличивать длительность выполнения этой таски?
1. Неоптимальные правила
Обычно это правила с условием, например, такие встречаются в библиотеке kotlinx-serialization. На них тратится больше всего времени, нужно быть аккуратнее с такими правилами и не дублировать их в своём коде, так как правила для R8 уже поставляются вместе с библиотеками.
2. Огромное количество ресурсов
Таска shrinkResources может потреблять очень много оперативной памяти, и если в вашей дизайн-системе вы предоставляете большую библиотеку иконок, то, возможно, стоит пересмотреть подход и не тащить тысячи иконок, чтобы потом R8 не удалял их очень долго. Как вариант, можно рассмотреть загрузку иконок с CDN по запросу.
А главная проблема в том, что добавление любой библиотеки в проект или изменение правил в одном из модулей может сказаться на времени сборки всего проекта, поэтому нужно не забивать на мониторинг времени сборки приложения и вовремя реагировать на изменения.
#R8 #Gradle
Please open Telegram to view this post
VIEW IN TELEGRAM
На сегодняший день есть множество либ для сканирования QR-кодов, но к сожалению, далеко не все из них справляются с разными видами Data Matrix.
Ранее мы использовали Google ML Kit, но он очень плох при сканировании Data Matrix, а из других бесплатных аналогов остается только ZXing или его адаптированная под Android версия, обе из которых уже давно не развиваются.
Мы сейчас проводим исследование библиотек для сканирования Data Matrix и хотели бы узнать, какие библиотеки вы используете. Напишите, пожалуйста, в комментариях какую либу вы рекомендуете, если у вас был такой опыт💬
Ранее мы использовали Google ML Kit, но он очень плох при сканировании Data Matrix, а из других бесплатных аналогов остается только ZXing или его адаптированная под Android версия, обе из которых уже давно не развиваются.
Мы сейчас проводим исследование библиотек для сканирования Data Matrix и хотели бы узнать, какие библиотеки вы используете. Напишите, пожалуйста, в комментариях какую либу вы рекомендуете, если у вас был такой опыт
Please open Telegram to view this post
VIEW IN TELEGRAM
Зачем мигрировать на котлиновский UUID?
Вы, наверное, слышали, что в Kotlin появился встроенный генератор UUID, который можно использовать в общем коде. Но он всё ещё экспериментальный, да и вообще написать expect/actual функцию можно в одну строчку. Поэтому, думаю, многие даже и не задумывались о переходе в KMP-проектах. Но на самом деле это имеет смысл.
Проблема с подходом expect/actual заключается в том, что UUID под iOS будет генерироваться в верхнем регистре, и это может привести к проблемам. Например:
Представим, что вы работаете с чатом и сохраняете какое-то сообщение с неким ID в БД и отправляете его же на сервер. Но при следующей загрузке данных с бэкенда вам возвращается это сообщение с ID в нижнем регистре. Если вы использовали обычный SQL-запрос для поиска сообщения по ID, то ничего не найдёте, потому что регистр отличается. В то время как на Android всё будет работать корректно.
Таким образом, использование нового механизма генерации поможет избежать этой проблемы, так как UUID будет генерироваться в одном виде на всех платформах. Помимо этого вы получаете лучшую типобезопасность, так как можете вместо String использовать Uuid для всех идентификаторов в вашем коде.
#KMP #Kotlin
Вы, наверное, слышали, что в Kotlin появился встроенный генератор UUID, который можно использовать в общем коде. Но он всё ещё экспериментальный, да и вообще написать expect/actual функцию можно в одну строчку. Поэтому, думаю, многие даже и не задумывались о переходе в KMP-проектах. Но на самом деле это имеет смысл.
Проблема с подходом expect/actual заключается в том, что UUID под iOS будет генерироваться в верхнем регистре, и это может привести к проблемам. Например:
Представим, что вы работаете с чатом и сохраняете какое-то сообщение с неким ID в БД и отправляете его же на сервер. Но при следующей загрузке данных с бэкенда вам возвращается это сообщение с ID в нижнем регистре. Если вы использовали обычный SQL-запрос для поиска сообщения по ID, то ничего не найдёте, потому что регистр отличается. В то время как на Android всё будет работать корректно.
Таким образом, использование нового механизма генерации поможет избежать этой проблемы, так как UUID будет генерироваться в одном виде на всех платформах. Помимо этого вы получаете лучшую типобезопасность, так как можете вместо String использовать Uuid для всех идентификаторов в вашем коде.
#KMP #Kotlin
Обычно SwiftUI и Compose очень похожи между собой, и, как правило, стейт для экранов можно формировать одинаково — это очень удобно при работе с KMP.
Но иногда бывают сильные отличия в API, например, PullToRefresh: если в Compose индикатор показывается по изменению состояния, то в SwiftUI — это асинхронная таска🤬
Недавно мы наткнулись на ещё один такой компонент — контекстное меню. На слайде видно, насколько более громоздко выглядит код на Compose, но не все так однозначно. Здесь разница в том, что, опять же, если в Compose меню показывается в зависимости от состояния, то в SwiftUI мы сразу должны знать, какие элементы отображать в этом меню, и нельзя сделать это по клику. Это неудобно, если элементы контекстного меню формируются динамически.
Чтобы исправить это, придётся в стейте сразу хранить словарь и в зависимости от типа ячейки, на которую кликнули, выбирать нужный набор значений.
💬 А какие ошибки допускали вы при формировании стейта экрана?
#Compose #SwiftUI
Но иногда бывают сильные отличия в API, например, PullToRefresh: если в Compose индикатор показывается по изменению состояния, то в SwiftUI — это асинхронная таска
Недавно мы наткнулись на ещё один такой компонент — контекстное меню. На слайде видно, насколько более громоздко выглядит код на Compose, но не все так однозначно. Здесь разница в том, что, опять же, если в Compose меню показывается в зависимости от состояния, то в SwiftUI мы сразу должны знать, какие элементы отображать в этом меню, и нельзя сделать это по клику. Это неудобно, если элементы контекстного меню формируются динамически.
Чтобы исправить это, придётся в стейте сразу хранить словарь и в зависимости от типа ячейки, на которую кликнули, выбирать нужный набор значений.
#Compose #SwiftUI
Please open Telegram to view this post
VIEW IN TELEGRAM
Маст-хэв кастомные Gradle-плагины
Если вы разрабатываете несколько приложений, то наверняка уже шарите какой-то общий код, вынося его в отдельные библиотеки или модули. Но не только общие модули могут быть полезны — можно ещё переиспользовать утилитарный код с помощью Gradle-плагинов.
Знаю, что многие, мягко говоря, не любят Gradle — и на то есть причины. Однако написание собственного небольшого плагина проще, чем кажется, особенно если делать это неправильно (привет afterEvaluate🙃 ).
Вот несколько идей для плагинов, которые могут быть полезны:
1️⃣ Version Catalog — очень простой плагин, который помогает удобно переиспользовать версии зависимостей между проектами. Про него я уже как-то писал здесь.
2️⃣ Code Style — обёртка над Detekt с настроенными дефолтными и кастомными правилами.
3️⃣ Git Hook — запуск тестов и проверки кода при коммите, проверка сообщения коммита и прочее.
4️⃣ Vault — плагин для получения секретов из защищённого хранилища при первоначальной настройке проекта.
5️⃣ Publish — плагин для упрощения публикации собственных плагинов, каталога версий, Android и KMP-библиотек.
🔥 Если тема интересна — ставьте реакции, и я расскажу подробнее, как создавать такие плагины и дам рекомендации как не стоит делать.
#Gradle
Если вы разрабатываете несколько приложений, то наверняка уже шарите какой-то общий код, вынося его в отдельные библиотеки или модули. Но не только общие модули могут быть полезны — можно ещё переиспользовать утилитарный код с помощью Gradle-плагинов.
Знаю, что многие, мягко говоря, не любят Gradle — и на то есть причины. Однако написание собственного небольшого плагина проще, чем кажется, особенно если делать это неправильно (привет afterEvaluate
Вот несколько идей для плагинов, которые могут быть полезны:
#Gradle
Please open Telegram to view this post
VIEW IN TELEGRAM
Действительно, стало гораздо проще адаптировать какой-нибудь простой Jetpack Compose-пример на iOS, буквально перенося файлы из одной папки в другую, но с реальными приложениями всё не так гладко. И вот какие проблемы я вижу на текущий момент:
Во Flutter, например, есть огромное количество библиотек на любой вкус и цвет, которые покрывают все платформенные API в общем коде: работу с разрешениями, камерой, геолокацией и другими. В CMP же в большинстве случаев придётся реализовывать это нативно, что требует хотя бы минимальных знаний платформы и языка.
Сейчас «из коробки» доступны только Material-виджеты, и, несмотря на то что у многих приложений своя дизайн-система, всё равно хотелось бы адаптировать часть виджетов под платформу. Например, Android-овский PullToRefresh выглядит максимально инородно на iOS и в целом плохо дружит с физикой скролла на iOS.
В анонсе сказано, что производительность CMP сравнима со SwiftUI и, судя по графикам, даже превосходит его. Но это всего лишь один бенчмарк ленивого списка. Если вы начнёте сравнивать приложение на SwiftUI и CMP на каком-нибудь iPhone 13, то невооружённым глазом увидите разницу не в пользу Compose. Очевидно, что проблема кроется в Skia, от которой Flutter и отказался из-за проблем с производительностью. Будем надеяться, что в будущем команда CMP тоже предпримет какие-то шаги в этом направлении.
#ComposeMultiplatform #CMP
Please open Telegram to view this post
VIEW IN TELEGRAM
Курс "Kotlin JVM - для начинающих", прошедший через два года улучшений, и теперь о нём не стыдно рассказать 🙂
✨ Чем отличается курс:
- Научно-фантастическая тематика задач
- Более 50 часов практики (300 практических задач, а также 11 мини-проектов)
- Подробная теория, подкрепленная примерами с решениями
- Плавная кривая обучения
- И много других отличий, о которых можно почитать в отзывах
✅ Курс на платформе Stepik: https://stepik.org/a/130490/?erid=2VtzqxZcP9E
🎊 Сайт с промокодами: https://android-for-juniors.ru/?erid=2VtzqxZcP9E
P.S. Первые модули открыты для ознакомления с форматом подачи материала 🧩
#реклама
✨ Чем отличается курс:
- Научно-фантастическая тематика задач
- Более 50 часов практики (300 практических задач, а также 11 мини-проектов)
- Подробная теория, подкрепленная примерами с решениями
- Плавная кривая обучения
- И много других отличий, о которых можно почитать в отзывах
✅ Курс на платформе Stepik: https://stepik.org/a/130490/?erid=2VtzqxZcP9E
🎊 Сайт с промокодами: https://android-for-juniors.ru/?erid=2VtzqxZcP9E
P.S. Первые модули открыты для ознакомления с форматом подачи материала 🧩
#реклама
UI-тестирование в Compose 🎨
Если вы хотите реализовать UI-тесты в Compose, то на сегодняшний день есть три основных решения: официальная библиотека от Google и обёртки над ней — Kakao/Kaspresso и Ultron. Про официальное решение сегодня говорить не будем, а рассмотрим поближе другие библиотеки.
Мы уже много лет используем Kaspresso для UI-тестов, но недавно я решил поближе познакомиться с библиотекой Ultron и сравнить оба решения. На самом деле, по функциональности они очень схожи.
🟡 Ultron выглядит довольно заманчиво: у него есть два ключевых преимущества перед конкурентами — при написании тестов на Ultron практически отсутствует какой-либо бойлерплейт-код, а также Ultron поддерживает Compose Multiplatform. Ещё из плюсов можно выделить качественную документацию. Из недостатков я бы отметил довольно небольшое комьюнити у библиотеки, а также, лично для меня, оказалось непривычным отсутствие связей parent-child между PageObject. Подробнее узнать про Ultron можно в недавно опубликованном докладе от автора библиотеки — Алексея Тюрина.
🔘 Kakao/Kaspresso — проверенные временем библиотеки с большим комьюнити, но описание PageObject в Kakao до версии 1.0 требовало довольно много бойлерплейт-кода, особенно при работе с Lazy-списками. Также механизм flaky safety в Kaspresso не совсем хорошо работает с виртуальным временем в Compose-тестах. Об этом подробно рассказал Паша Стрельченко в своём докладе.
💬 А что используете вы для UI-тестирования в Compose? И оправдан ли тренд на уход от дорогих UI-тестов в проекте?
#Compose #UiTesting
Если вы хотите реализовать UI-тесты в Compose, то на сегодняшний день есть три основных решения: официальная библиотека от Google и обёртки над ней — Kakao/Kaspresso и Ultron. Про официальное решение сегодня говорить не будем, а рассмотрим поближе другие библиотеки.
Мы уже много лет используем Kaspresso для UI-тестов, но недавно я решил поближе познакомиться с библиотекой Ultron и сравнить оба решения. На самом деле, по функциональности они очень схожи.
💬 А что используете вы для UI-тестирования в Compose? И оправдан ли тренд на уход от дорогих UI-тестов в проекте?
#Compose #UiTesting
Please open Telegram to view this post
VIEW IN TELEGRAM
Решил я, значит, повайбкодить и сделать CLI-приложение на Kotlin для сканирования Data Matrix с помощью библиотеки ZXing. На вход бы передавался архив с датасетом из реальных изображений продуктов с кодами, а на выходе получали бы отчёт: какие Data Matrix удалось распарсить, а какие — нет.
Первую версию я сделал с помощью ChatGPT, и, несмотря на то что модельки стали писать рабочий код с первого раза, результат получился катастрофическим — распозналось всего 10% Data Matrix из всего датасета на тысячи кодов. Зато работало это довольно быстро.
Далее я попробовал все последние модели, доступные без платной подписки: GPT-4o, Gemini 2.5 Flash, Deepseek R1, Claude Sonnet 4 и Grok 3. Попросил их улучшить текущее распознавание кодов.
В итоге во всех случаях я получил решение, работающее в сотню раз медленнее, которое либо давало тот же результат, либо вообще ничего не сканировало🤡
Единственным, кто смог хоть что-то улучшить со второй попытки, оказался Grok — но и то разница получилась не драматической: условно, из 20 кодов распозналось не 2, а 4.
Так что на этом мой вайбкодинг закончился — придётся дальше всё делать самому🥲
Первую версию я сделал с помощью ChatGPT, и, несмотря на то что модельки стали писать рабочий код с первого раза, результат получился катастрофическим — распозналось всего 10% Data Matrix из всего датасета на тысячи кодов. Зато работало это довольно быстро.
Далее я попробовал все последние модели, доступные без платной подписки: GPT-4o, Gemini 2.5 Flash, Deepseek R1, Claude Sonnet 4 и Grok 3. Попросил их улучшить текущее распознавание кодов.
В итоге во всех случаях я получил решение, работающее в сотню раз медленнее, которое либо давало тот же результат, либо вообще ничего не сканировало
Единственным, кто смог хоть что-то улучшить со второй попытки, оказался Grok — но и то разница получилась не драматической: условно, из 20 кодов распозналось не 2, а 4.
Так что на этом мой вайбкодинг закончился — придётся дальше всё делать самому
Please open Telegram to view this post
VIEW IN TELEGRAM
Фоновая работа в Android и iOS
Бытует мнение, что iOS вообще не позволяет приложению выполнять какие-либо действия в фоне, но это не совсем так. В одном из наших Compose Multiplatform приложений необходимо было реализовать синхронизацию данных в фоне, и моему коллеге пришлось глубже разобраться в теме.
➖ На текущий момент не существует хорошего решения для KMP-проектов, которое предоставляло бы общий API для работы с фоновыми задачами. Это вполне объяснимо: API сильно отличаются между платформами.
🤖 Для решения задачи синхронизации данных в фоне в Android существует несколько решений, например, WorkManager, который имеет довольно удобный API и позволяет запускать задачи с интервалом не менее 15 минут. Он позволяет задать условия запуска задачи, порядок выполнения воркеров и определить поведение при повторном планировании одной и той же задачи.
🍏 В iOS есть два стула: BGAppRefreshTaskRequest и BGProcessingTaskRequest.
Первый предназначен для относительно быстрых операций длительностью до 30 секунд и может выполняться чаще, второй — для более долгих задач, которые могут выполняться в течение нескольких минут и даже часов. Разумеется, можно указать минимальное время, через которое должна быть выполнена синхронизация. В интернетах рекомендуют устанавливать интервал в один час, однако iOS конечно же не гарантирует, что задача будет выполнена вообще🙃
С появлением SwiftUI стало удобнее работать с фоновыми задачами — достаточно запланировать их с помощью BGTaskScheduler и обрабатывать через модификатор backgroundTask. Однако, по сравнению с WorkManager, многое приходится делать вручную — например, явно обрабатывать ситуацию, когда задача уже запланирована, иначе интервал её запуска может быть сброшен.
📌 Таким образом, реализовать фоновую работу в мультиплатформенных проектах вполне возможно, но для этого потребуется написать платформенный код.
#iOS #Android #Background #KMP
Бытует мнение, что iOS вообще не позволяет приложению выполнять какие-либо действия в фоне, но это не совсем так. В одном из наших Compose Multiplatform приложений необходимо было реализовать синхронизацию данных в фоне, и моему коллеге пришлось глубже разобраться в теме.
Первый предназначен для относительно быстрых операций длительностью до 30 секунд и может выполняться чаще, второй — для более долгих задач, которые могут выполняться в течение нескольких минут и даже часов. Разумеется, можно указать минимальное время, через которое должна быть выполнена синхронизация. В интернетах рекомендуют устанавливать интервал в один час, однако iOS конечно же не гарантирует, что задача будет выполнена вообще
С появлением SwiftUI стало удобнее работать с фоновыми задачами — достаточно запланировать их с помощью BGTaskScheduler и обрабатывать через модификатор backgroundTask. Однако, по сравнению с WorkManager, многое приходится делать вручную — например, явно обрабатывать ситуацию, когда задача уже запланирована, иначе интервал её запуска может быть сброшен.
#iOS #Android #Background #KMP
Please open Telegram to view this post
VIEW IN TELEGRAM
Хочу порекомендовать вам классный канал Dev Easy Notes про разработку на около-андроидную тематику и не только. Там можно найти много всего интересного:
🔘 Серия постов о том, как работает Android
🔘 Когда нужно использовать статику вместо DI
🔘 Что не так с книгой "Чистый код"
🔘 Самое странное собеседование
🔘 Серия постов про то, как работает CI
На канале нет бесконечных репостов с Medium, зато есть качественный авторский контент с щепоткой хорошего юмора. Так что, если хотите прокачиваться не только в мобильной разработке, этот канал определённо будет вам полезен😉
На канале нет бесконечных репостов с Medium, зато есть качественный авторский контент с щепоткой хорошего юмора. Так что, если хотите прокачиваться не только в мобильной разработке, этот канал определённо будет вам полезен
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Dev Easy Notes
Работаю в IT уже 8 лет. Рассказываю про разработку простым языком. Полезность скрыта под тупыми шутками и слоем мата. Лучший underground канал про разработку, который вы сможете найти.
По сотрудничеству писать @haroncode
По сотрудничеству писать @haroncode
Расскажу историю про забавный факап с Unit-тестами — когда тесты не прогонялись, но никто этого не замечал.
Сейчас мы все такие модные и молодёжные: пишем KMP-проекты и запускаем тесты через Gradle-таску
В обычных Android-проектах для запуска Unit-тестов есть стандартная таска
Но когда в проекте появляются Flavors (да, это зло, но иногда вынужденное), то для модуля app, где эти Flavors описаны, нужная таска превращается в🌟
А если в других модулях Flavors нет, то тесты по этой таске просто не прогоняются! Для них нужно явно вызывать таску без Flavor.
Звучит очень глупо — как можно было так ошибиться? Но когда ты видишь зелёный pipeline, в голову почему-то не приходит специально сломать какой-нибудь тест в отдельном модуле, чтобы проверить, что всё работает🌟
Вот такая вот кринж-история. А какие факапы были у вас?
Сейчас мы все такие модные и молодёжные: пишем KMP-проекты и запускаем тесты через Gradle-таску
allTests
, которая прогоняет все тесты в проекте и даже делает это на всех таргетах, если тесты написаны в общем коде.В обычных Android-проектах для запуска Unit-тестов есть стандартная таска
test
, которая прогоняет тесты для всех BuildVariant. В своё время мы подумали: а зачем гонять тесты вхолостую, тратить больше времени? Достаточно же прогнать только релизную сборку — testReleaseUnitTest
.Но когда в проекте появляются Flavors (да, это зло, но иногда вынужденное), то для модуля app, где эти Flavors описаны, нужная таска превращается в
test<Flavor><BuildType>UnitTest
. Мы были уверены, что, запустив её, все тесты в других модулях тоже выполнятся. Но, конечно же, никто ничего не проверил А если в других модулях Flavors нет, то тесты по этой таске просто не прогоняются! Для них нужно явно вызывать таску без Flavor.
Звучит очень глупо — как можно было так ошибиться? Но когда ты видишь зелёный pipeline, в голову почему-то не приходит специально сломать какой-нибудь тест в отдельном модуле, чтобы проверить, что всё работает
Вот такая вот кринж-история. А какие факапы были у вас?
Please open Telegram to view this post
VIEW IN TELEGRAM
Must-have материалы для углубления в Compose
Если вы хотели глубже разобраться в Compose, то ловите список материалов в открытом доступе, которые точно заслуживают вашего внимания:
Доклады
- Мой доклад о том, что скрывает стейт в Compose
- Наш с Димой Григорьевым квиз по Compose
- Доклады от Димы о том, как работает позиционная мемоизация и как устроена композиция в Compose
- Доклад от Асахра Айдарова про устройство компиляторного плагина в Compose
- Доклад от Алексея Гладкова про то, как работает Compose for iOS
- Доклад от Leland Richardson. Как работают модификаторы [en]
- Доклад про создание UI фреймворка для PowerPoint на основе Compose Runtime [en].
- Хардкорный доклад от Jake Wharton про запуск Compose на контроллере от настольной лампы [en].
Репозитории
- Пример реализации автоматических анимаций на основе состояния
- Репозиторий с реализацией анимаций разной сложности
- Compose для терминала от Jake Wharton
Блоги
- Compose Broadcast
- Mobile Compose
- Блог от Zach Klippenstein [en]
Книги
- Jetpack Compose Internals - Jorge Castillo
Ну и не забывайте про официальную документацию — там целая кладезь полезной инфы про Compose, которую часто просто копируют авторы различных статей на Medium.
Если вы знаете ещё какие-то интересные материалы про устройство Compose, то обязательно делитесь ссылками в комментариях⬇️
Если вы хотели глубже разобраться в Compose, то ловите список материалов в открытом доступе, которые точно заслуживают вашего внимания:
Доклады
- Мой доклад о том, что скрывает стейт в Compose
- Наш с Димой Григорьевым квиз по Compose
- Доклады от Димы о том, как работает позиционная мемоизация и как устроена композиция в Compose
- Доклад от Асахра Айдарова про устройство компиляторного плагина в Compose
- Доклад от Алексея Гладкова про то, как работает Compose for iOS
- Доклад от Leland Richardson. Как работают модификаторы [en]
- Доклад про создание UI фреймворка для PowerPoint на основе Compose Runtime [en].
- Хардкорный доклад от Jake Wharton про запуск Compose на контроллере от настольной лампы [en].
Репозитории
- Пример реализации автоматических анимаций на основе состояния
- Репозиторий с реализацией анимаций разной сложности
- Compose для терминала от Jake Wharton
Блоги
- Compose Broadcast
- Mobile Compose
- Блог от Zach Klippenstein [en]
Книги
- Jetpack Compose Internals - Jorge Castillo
Ну и не забывайте про официальную документацию — там целая кладезь полезной инфы про Compose, которую часто просто копируют авторы различных статей на Medium.
Если вы знаете ещё какие-то интересные материалы про устройство Compose, то обязательно делитесь ссылками в комментариях
Please open Telegram to view this post
VIEW IN TELEGRAM
Думаю, никто не будет спорить, что в нашей сфере английский язык очень важен: нужно уметь читать документацию, смотреть доклады из первых уст, но одного знания технического английского мало.
Если вы хотите проходить собеседования в зарубежные компании, нужно также уметь говорить по-английски, а прокачать этот навык можно только на практике, например, занимаясь с преподавателем.
Я хочу порекомендовать вам классного преподавателя — Кирилла Моисеева. Я сам у него занимался и могу сказать, что он горит своим делом и практикует олдскульный подход к обучению, направленный на то, чтобы вы как можно быстрее заговорили на английском.
Так что, если вы искали отличного преподавателя, пишите @mainsdorff_bot, чтобы записаться на урок😉
#Рекомендация
Если вы хотите проходить собеседования в зарубежные компании, нужно также уметь говорить по-английски, а прокачать этот навык можно только на практике, например, занимаясь с преподавателем.
Я хочу порекомендовать вам классного преподавателя — Кирилла Моисеева. Я сам у него занимался и могу сказать, что он горит своим делом и практикует олдскульный подход к обучению, направленный на то, чтобы вы как можно быстрее заговорили на английском.
Так что, если вы искали отличного преподавателя, пишите @mainsdorff_bot, чтобы записаться на урок
#Рекомендация
Please open Telegram to view this post
VIEW IN TELEGRAM
Telegram
Кирилл Моисеев — преподаватель английского
Помогаю профессионалам развивать английский и достигать карьерных целей 🚀
Жизнь программиста в Лондоне
🏝 Последние две недели я отдыхал в Лондоне, встретился с инженерами из разных компаний — от стартапов до бигтеха, вроде Amazon и 𝕏. И захотелось написать небольшой пост на тему: стоит ли вообще переезжать сюда инженеру или нет.
🇬🇧 Лондон — очень большой и красивый город, но в то же время очень дорогой. Например, здесь самый дорогой общественный транспорт в мире, а про стоимость покупки собственного жилья можно даже не говорить.
💸 Отсюда вытекает главный нюанс: чтобы хорошо жить здесь, нужно также хорошо зарабатывать. Средняя зарплата программиста здесь — около £50k / y, которой едва хватит, чтобы снимать жильё и питаться. А чтобы найти хотя бы приемлемые для жизни 100k, не в бигтехе, нужно сильно постараться.
🤔 Переезжают в Лондон обычно по двум типам виз: либо Skilled Worker, либо Global Talent Visa. В первом случае вы привязаны к работодателю, во втором у вас больше свободы, и при поиске работы вы будете конкурировать с местными, а не со всем миром.
👑 Так что, если решить финансовые вопросы, это отличный город для жизни. Здесь множество зелёных парков, красивые улицы, зрелищные постановки в театрах, приятный климат и многое другое. Но, разумеется, есть и минусы: не самые лучшие сервисы, средняя местная еда, отсутствие детских площадок и относительно высокий уровень преступности в некоторых районах.
А вы бы переехали в UK?
🇬🇧 Лондон — очень большой и красивый город, но в то же время очень дорогой. Например, здесь самый дорогой общественный транспорт в мире, а про стоимость покупки собственного жилья можно даже не говорить.
А вы бы переехали в UK?
Please open Telegram to view this post
VIEW IN TELEGRAM
Как подружить LifecycleOwner и Decompose
Некоторые API в Jetpack библиотеках принимают в качестве параметра LifecycleOwner, например, так сделано в CameraX. Однако если в вашем проекте используется Decompose, и вы используете LocalLifecycleOwner для получения текущего значения в Composable функции, то жизненный цикл будет работать некорректно: он будет соответствовать жизненному циклу Activity или Fragment, так как Decompose нигде не переопределяет этот CompositionLocal и использует собственный жизненный цикл из библиотеки Essenty.
Чтобы исправить эту проблему, необходимо сконвертировать LifecycleOwner из Decompose в его аналог из Jetpack. Однако из коробки пока что такого адаптера нет, и придётся написать его самостоятельно, по аналогии с конвертацией ЖЦ в Essenty.
В версии Decompose 3.4.0 эта проблема будет решаться проще: появится JetpackComponentContext, как отдельная зависимость, и можно будет сразу получить нужный lifecycle прямо из компонента.
Поэтому будьте внимательны при использовании CompositionLocal для работы с жизненным циклом, если навигация в проекте построена на Decompose.
#Decompose #Lifecycle
Некоторые API в Jetpack библиотеках принимают в качестве параметра LifecycleOwner, например, так сделано в CameraX. Однако если в вашем проекте используется Decompose, и вы используете LocalLifecycleOwner для получения текущего значения в Composable функции, то жизненный цикл будет работать некорректно: он будет соответствовать жизненному циклу Activity или Fragment, так как Decompose нигде не переопределяет этот CompositionLocal и использует собственный жизненный цикл из библиотеки Essenty.
Чтобы исправить эту проблему, необходимо сконвертировать LifecycleOwner из Decompose в его аналог из Jetpack. Однако из коробки пока что такого адаптера нет, и придётся написать его самостоятельно, по аналогии с конвертацией ЖЦ в Essenty.
В версии Decompose 3.4.0 эта проблема будет решаться проще: появится JetpackComponentContext, как отдельная зависимость, и можно будет сразу получить нужный lifecycle прямо из компонента.
Поэтому будьте внимательны при использовании CompositionLocal для работы с жизненным циклом, если навигация в проекте построена на Decompose.
#Decompose #Lifecycle
Время выглянуть за рамки мониторов и взять в руки удочку
Сделайте паузу от тасков и митов на летнем IT-фестивале от Selectel против выгорания!
🗓 27 июля
📍 Флагшток, Санкт-Петербург или онлайн
В программе:
- доклады и воркшопы о том, как встроить отдых в свой плотный график,
- жизненные выступления на IT-стендапе,
- возможность попробовать разные активности, чтобы найти новое хобби: скалолазание, бокс, кастом вещей, рыбалка
Участие бесплатное, нужно просто зарегистрироваться: https://slc.tl/kmc8s
А чтобы посмотреть полную программу, заглянуть за кулисы подготовки и поучаствовать в розыгрыше лимитированного тирекса, подписывайтесь на @Selectel_Events
Сделайте паузу от тасков и митов на летнем IT-фестивале от Selectel против выгорания!
🗓 27 июля
📍 Флагшток, Санкт-Петербург или онлайн
В программе:
- доклады и воркшопы о том, как встроить отдых в свой плотный график,
- жизненные выступления на IT-стендапе,
- возможность попробовать разные активности, чтобы найти новое хобби: скалолазание, бокс, кастом вещей, рыбалка
Участие бесплатное, нужно просто зарегистрироваться: https://slc.tl/kmc8s
А чтобы посмотреть полную программу, заглянуть за кулисы подготовки и поучаствовать в розыгрыше лимитированного тирекса, подписывайтесь на @Selectel_Events
Как встроить SwiftUI в Compose Multiplatform
Обычно я стараюсь избегать использования кастомных CompositionLocal в Compose, так как это добавляет неявные зависимости, и если не предоставить значение, приложение упадёт в рантайме. Я придерживаюсь подхода, в котором CompositionLocal можно использовать только тогда, когда значение действительно может быть полезно любой Composable-функции в дереве. Яркий пример — тема приложения.
И при работе с Compose Multiplatform я подсмотрел классное применение этого механизма для встраивания SwiftUI вьюшек в Composable функции.
1. В сорсете iosMain создаём CompositionLocal и интерфейс NativeViewFactory.
2. На стороне Swift реализуем этот интерфейс и передаём его в функцию создания UIViewController.
3. В этой функции пробрасываем фабрику через CompositionLocalProvider.
4. Далее в любом месте поддерева в iosMain можно получить доступ к этой нативной вьюшке.
🌐 Посмотреть пример приложения для сканирования QR-кодов с этим подходом можно в репозитории, который я подготовил для лекции в онлайн-университете.
#Compose #SwiftUI
Обычно я стараюсь избегать использования кастомных CompositionLocal в Compose, так как это добавляет неявные зависимости, и если не предоставить значение, приложение упадёт в рантайме. Я придерживаюсь подхода, в котором CompositionLocal можно использовать только тогда, когда значение действительно может быть полезно любой Composable-функции в дереве. Яркий пример — тема приложения.
И при работе с Compose Multiplatform я подсмотрел классное применение этого механизма для встраивания SwiftUI вьюшек в Composable функции.
1. В сорсете iosMain создаём CompositionLocal и интерфейс NativeViewFactory.
2. На стороне Swift реализуем этот интерфейс и передаём его в функцию создания UIViewController.
3. В этой функции пробрасываем фабрику через CompositionLocalProvider.
4. Далее в любом месте поддерева в iosMain можно получить доступ к этой нативной вьюшке.
#Compose #SwiftUI
Please open Telegram to view this post
VIEW IN TELEGRAM