Forwarded from Mobile Native ️️
Маяк в пустыне: Kotlin DSL для Android-шейдеров
В статье автор рассказывает про сложности и неудобства работы с шейдерами в Android, из-за чего он заморочился и написал библиотеку, которая оборачивает всё это добро в типизированный Kotlin DSL.
👉 почему голый AGSL в Android-коде быстро начинает утомлять
👉 как выглядит тот же шейдер в RedByteFX
👉 четыре учебных примера - от простого к сложным эффектам
👉 как устроен DSL: координаты, uniform-ы, let(...), fn(...), sample(), sampleUv(), стандартная библиотека и интеграция с Compose;
👉 где библиотека реально выигрывает, а где у неё есть честные ограничения.
Библиотека на GitHub → RedByteFX
Читать (Ru)
В статье автор рассказывает про сложности и неудобства работы с шейдерами в Android, из-за чего он заморочился и написал библиотеку, которая оборачивает всё это добро в типизированный Kotlin DSL.
👉 почему голый AGSL в Android-коде быстро начинает утомлять
👉 как выглядит тот же шейдер в RedByteFX
👉 четыре учебных примера - от простого к сложным эффектам
👉 как устроен DSL: координаты, uniform-ы, let(...), fn(...), sample(), sampleUv(), стандартная библиотека и интеграция с Compose;
👉 где библиотека реально выигрывает, а где у неё есть честные ограничения.
Библиотека не подменяет исполнение, нативный AGSL по-прежнему исполняется на устройстве и работает по принципу Kotlin DSL → сгенерированный AGSL → RuntimeShader / RenderEffect.
Библиотека на GitHub → RedByteFX
Читать (Ru)
Forwarded from Mobile Native ️️
Kotlin Coroutine bridges: converting any callback-based Android API to suspend functions
Полезная статья, в которой показывается, как можно преобразовывать любые коллбэк-ориентированные Android API в suspend-функции используя suspendCoroutine.
👉 The fundamental problem: Callbacks do not compose
👉 The core bridge: suspendCoroutine
👉 Success and error callbacks: The two-path bridge
👉 The callback factory: Abstracting interface boilerplate
👉 Multi-value callbacks: Wrapper classes
👉 Exception hierarchies: Preserving error semantics
👉 The Result<T> variant: Exceptions are not always what you want
👉 The lambda convenience layer: Bridging before the bridge
👉 Real-world application: Bridging Google Play Billing directly
👉 suspendCoroutine versus suspendCancellableCoroutine
👉 Applying the pattern beyond billing
👉 Common mistakes to avoid
Читать (En)
Полезная статья, в которой показывается, как можно преобразовывать любые коллбэк-ориентированные Android API в suspend-функции используя suspendCoroutine.
👉 The fundamental problem: Callbacks do not compose
👉 The core bridge: suspendCoroutine
👉 Success and error callbacks: The two-path bridge
👉 The callback factory: Abstracting interface boilerplate
👉 Multi-value callbacks: Wrapper classes
👉 Exception hierarchies: Preserving error semantics
👉 The Result<T> variant: Exceptions are not always what you want
👉 The lambda convenience layer: Bridging before the bridge
👉 Real-world application: Bridging Google Play Billing directly
👉 suspendCoroutine versus suspendCancellableCoroutine
👉 Applying the pattern beyond billing
👉 Common mistakes to avoid
Читать (En)
Forwarded from Android Live 🤖
Koin Migration
Ещё один MCP в копилку. Разработчики из Koin написали тулзу, которая поможет мигрировать текущий проект практически с любого DI-фреймворка на Koin.
Полагаю, что современные языковые модели в какой-то степени справятся с этой задачей и самостоятельно, но с данным решением переезд станет гораздо комфортнее.
Люблю Koin, считаю его одним из самых удачных dependency-библиотек.
Ещё один MCP в копилку. Разработчики из Koin написали тулзу, которая поможет мигрировать текущий проект практически с любого DI-фреймворка на Koin.
Полагаю, что современные языковые модели в какой-то степени справятся с этой задачей и самостоятельно, но с данным решением переезд станет гораздо комфортнее.
Люблю Koin, считаю его одним из самых удачных dependency-библиотек.
GitHub
GitHub - InsertKoinIO/koin-migration: Koin + Koin Compiler Plugin migration — reference docs and AI skill that automate the move…
Koin + Koin Compiler Plugin migration — reference docs and AI skill that automate the move from Hilt/Dagger/Toothpick/Kodein/manual DI to the Koin Compiler Plugin. - InsertKoinIO/koin-migration
Forwarded from StartAndroid
Сначала Роман Елизаров выступил на Java Rock Star Meetup с докладом про опыт разработчика (DX,Developer Experience). По сути про то, как современный разработчик тратит слишком много сил не на бизнес-задачу, а на обслуживание сложности вокруг себя: выборы, переключения, бойлерплейт, инфраструктурную возню, разрозненные инструменты.
И не так давно нам попался отчет Chainguard Engineering Reality Report 2026. Это уже не взгляд одного сильного практика, а международный срез: 1200 инженеров и технологических руководителей из США, Великобритании, Германии и Франции рассказали, что именно сегодня ломает Developer Experience. Картина оказалась удивительно знакомой: рутина съедает время, поддержка и сопровождение побеждает инновации, инструменты не стыкуются между собой, AI помогает, но не магически, а ровно настолько, насколько хорошо встроен в процесс.
Нам показалось интересным не просто пересказать оба материала, а собрать в единую картину. Где выводы российского специалиста и международной команд рифмуются между собой. Где Елизаров идет глубже и объясняет причины. И где начинается самое интересное - то есть различия между глобальной картиной и тем, как эта тема ощущается на российской почве.
#development
https://habr.com/ru/companies/axiomjdk/articles/1023926/
Хабр
Опыт разработчика как экономика внимания
Привет, Хабр! Эта статья выросла из двух материалов, которые неожиданно хорошо коррелируют между собой. Источники: доклад Романа Елизарова ( @elizarov ) Отчет Chainguard Engineering Reality Report...
Forwarded from Kotlin Multiplatform Broadcast
🔥Главное произошло в KMP части - Flows теперь экспортируются в Swift как AsyncSequence по умолчанию. Это значит, что вся эта суета с обёртками и callback-based API просто исчезает. Пишешь Flow на Kotlin-стороне, Swift видит AsyncSequence, готово.
🔥 Swift packages теперь импортируются прямо в Gradle без всех этих танцев с CocoaPods. Firebase, другие iOS либы импортируются через build.gradle.kts как обычные зависимости.
🔥 Collection literals в экспериментальной стадии. Теперь не только в аннотациях. Сомнительно... ну ОКЭЙ!
🔗 Больше подробностей в документации и @kotlin_broadcast
#kotlin #kmp #swift #release
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Kotlin Multiplatform Broadcast
// Вместо
val shapes: MutableList<String> =
mutableListOf("triangle", "square", "circle")
// Можно будет использовать новый синтаксис
val shapes: MutableList<String> =
["triangle", "square", "circle"]
class DoubleMatrix(vararg val rows: Row) {
companion object {
operator fun of(vararg rows: Row) = DoubleMatrix(*rows)
}
class Row(vararg val elements: Double) {
companion object {
operator fun of(vararg elements: Double) = Row(*elements)
}
}
}
val identityMatrix: DoubleMatrix = [
[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0],
]Для тех кто создает много коллекций с наполнением станет проще. Но вот как часто кроме тестов приходится этим заниматься? Жил без литералов долго и ещё проживу
#Kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Kotlin Multiplatform Broadcast
Теперь работать с Kotlin Flow в KMP станет проще так как будет автоматическое конвертирование в удобный для Swift формат
fun flowOfStrings(): Flow<String> = flowOf("hello", "any", "world")var actual: [String] = []
// Type String is correctly inferred from Kotlin
for try await element in flowOfStrings().asAsyncSequence() {
actual.append(element)
}
🔗 Как настроить Swift to Kotlin Export
#Kotlin #Swift
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Compose Broadcast
В Compose 1.11.0 завезли новый интерфейс PreviewWrapper и аннотацию @PreviewWrapperProvider. Идея простая: вместо того чтобы оборачивать каждый Preview в свою тему, CompositionLocalProvider, моки навигации и прочее, ты один раз описываешь обёртку и просто навешиваешь её аннотацией.
Выглядит это так:
class ThemeWrapper : PreviewWrapper {
@Composable
override fun Wrap(content: @Composable () -> Unit) {
JetsnackTheme {
content()
}
}
}@PreviewWrapperProvider(ThemeWrapper::class)
@Preview
@Composable
private fun ButtonPreview() {
Button(onClick = {}) {
Text("Demo")
}
}
Сценарии где может пригодиться:
👉 встроить тему в превью
👉 подложить FakeNavController или LocalActivity
👉 обернуть в Hilt/Koin провайдер с тестовыми зависимостями
👉 прокинуть моки через CompositionLocal
Раньше для этого либо городили собственную функцию и вызывали её руками в каждом превью, либо писали кастомные
@Preview аннотации с ограниченным набором параметров.‼️ ВАЖНО: фича работает только в Android Studio Panda 4 и выше. В более старых версиях аннотация просто проигнорируется.
#compose #jetpackcompose #android
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Good Reads
Strong Skipping Mode не делает типы stable, лишь позволяет skip’ать
Внутри много кода, а не воды для самопроверки
composable с unstable параметрами, если передан тот же самый объект по ссылке ===, тогда как stable типы по-прежнему сравниваются через equals() из-за этого он не помогает, если создаются новые инстансы (типа listOf(), copy()), и рекомпозиция всё равно происходит, поэтому stability позволяет пропускать перерисовку для разных объектов с одинаковыми данными, а Strong Skipping - это оптимизация для случаев с переиспользованием одной и той же ссылки, а не замена пониманию стабильностиВнутри много кода, а не воды для самопроверки
Forwarded from Mobile Compose
This media is not supported in your browser
VIEW IN TELEGRAM
#Compose #UI #Animation #Debugging
🎨 Compose 1.11.0 — Визуальная отладка анимаций
Shared Elements анимации и работа с Modifier.animatedBounds стали прозрачнее благодаря инструменту LookaheadAnimationVisualDebugging.
Ключевые возможности:
▫️ Прямо в Runtime можно увидеть траектории движения объектов и их целевые границы (target bounds).
▫️ Визуализация помогает понять, почему элемент «прыгает» или обрезается при переходе между экранами.
Инструмент полезен в первую очередь для сложных UI-переходов, где раньше приходилось полагаться только на логи и интуицию.
🎨 Mobile Compose 💬 Чат канала
♾
Shared Elements анимации и работа с Modifier.animatedBounds стали прозрачнее благодаря инструменту LookaheadAnimationVisualDebugging.
Ключевые возможности:
Инструмент полезен в первую очередь для сложных UI-переходов, где раньше приходилось полагаться только на логи и интуицию.
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Compose Broadcast
This media is not supported in your browser
VIEW IN TELEGRAM
#Compose
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Compose Broadcast
// Пример использования
LookaheadAnimationVisualDebugging(
overlayColor = Color(0x4AE91E63),
isEnabled = true,
multipleMatchesColor = Color.Green,
isShowKeylabelEnabled = false,
unmatchedElementColor = Color.Red,
) {
SharedTransitionLayout {
CompositionLocalProvider(
LocalSharedTransitionScope provides this,
) {
// your content
}
}
}
#Compose
Forwarded from Compose Broadcast
До недавнего времени стилизация компонентов в Compose делалась через параметры Composable функции (
color = ..., padding = ...) или модификаторы. Это работало, но могло приводить к:👉 избыточным рекомпозициям при смене состояний;
👉 дублированию кода для разных вариаций кнопок/карточек;
👉 сложностям с анимацией переходов между стилями.
Google представил Styles API (экспериментальный, о причинах такого статуса ниже) — новый подход, вдохновлённый CSS. Нужен Jetpack Compose 1.11.0 или свежее
Ключевые возможности
Стили вычисляются на этапах layout и drawing, минуя composition. Это значит, что изменение стиля (например, при наведении) не вызывает рекомпозицию родительских компонентов.
Без кучи
if/else и animate*AsState. Просто описываете стиль для каждого состояния (нажат, сфокусирован, включён, ошибка и т.д.).Переходы между состояниями анимируются автоматически с физическими параметрами (демпфирование, жёсткость). Не нужно писать
Animatable или Transition.// Пример использования стиля
// Определяем стиль для кнопки
val buttonStyle = Style {
default {
backgroundColor = Color.Blue
shape = RoundedCornerShape(8.dp)
}
pressed {
backgroundColor = Color.DarkBlue
scale = 0.98f
}
disabled {
backgroundColor = Color.Gray
alpha = 0.5f
}
}
// Используем
Button(
onClick = { /* ... */ },
style = buttonStyle, // ← вместо кучи параметров
enabled = isEnabled
) {
Text("Нажми меня")
}
style — новый параметр, который появляется у всех компонентов Material 3 и базовых (Box, Row, Column).⚠️ Styles API не заменяет модификаторы
Модификаторы остаются для позиционирования, кликов, размеров. Styles API заменяет только внутреннюю стилизацию (цвета, формы, тени, отступы внутри компонента). Это как разделение «темы» и «вёрстки».
API остаётся экспериментальным пока на него полностью не перейдет Material 3 Compose, чтобы учесть все необходиcмоти API и не делать breaking changes. По работе оно уже стабильно, но вот изменения в коде, возможно, будут.
🔗 Официальная документация
В целом с таким подходом уже привыкли работать в Android XML Layout, то почему бы сразу было его не использовать? Тем более в Compose плюсы очевидны!
#Compose #Material
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Kotlin Multiplatform Broadcast
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Good Reads
This media is not supported in your browser
VIEW IN TELEGRAM
Compose анимации без пересборки
Дебажить анимации трудно и долго. Hot reload помогает и тут. Внутри анимация
Дебажить анимации трудно и долго. Hot reload помогает и тут. Внутри анимация
Grid, кастомная анимация волны на Canvas, изменение типа анимации tween -> spring, изменение animateContentSizeHotSwan обновляет примитивы в обход компиляции Gradle, за счет этого и получается такой результатForwarded from Android Broadcast
🤯 Те кто использовал Jetpack Paging 3 знают насколько он может справиться только с базовыми сценариямми. Шаг влево или вправо - уже боль!
Сегодня хочу познакомить вас с альтернативой — библиотекой🐱 Paginator. Это KMP-решение для пагинации, которое решает те самые проблемы, где Paging 3 начинает "буксовать".
Paginator построен на отличной модели от Jetpack Paging 3: страница — это адресуемая ячейка в кэше, кэш — обычная структура данных, а навигация — обычные методы.
1️⃣ ✅ Адресуемые страницы
Прямые методы
2️⃣ ✅ Мутации по запросу
3️⃣ ✅ Сохраняемое состояние
Кэш — обычная структура данных, которую можно сериализовать через
4️⃣ ✅ Библиотека, а не фреймворк
Написан на чистом Kotlin без платформенных зависимостей и живёт в
5️⃣ ✅ Курсорная пагинация "из коробки"
Отдельный класс
🔗 Оригинальная статья на Хабре
🐱 Репозиторий Paginator
#Android #AndroidDev #KMP
Сегодня хочу познакомить вас с альтернативой — библиотекой
Paginator построен на отличной модели от Jetpack Paging 3: страница — это адресуемая ячейка в кэше, кэш — обычная структура данных, а навигация — обычные методы.
Прямые методы
goNextPage(), goPreviousPage() и jump(Bookmark). Deeplink на сообщение из пуша решается одной строкой.MutablePaginator предоставляет CRUD-операции: replace { it.id == 42 }, removeWhere { it.deleted }. Один лайк меняет один элемент без инвалидации всей страницы.Кэш — обычная структура данных, которую можно сериализовать через
kotlinx.serialization. Методы serializeToJson() и restoreFromJson() решают проблему Process Death без плясок с бубном.Написан на чистом Kotlin без платформенных зависимостей и живёт в
commonMain. Логика пагинации становится частью общего доменного слоя KMP, не копируется между платформами и не имеет двух реализаций.Отдельный класс
CursorPaginator с единой моделью состояний, транзакций и сериализации.Paginator — это не обёртка над Paging 3. Это другая модель, переосмысливающая ключевые типы. Обёртка просто не смогла бы дать ни мутации элемента, ни сериализации кэша.
🔗 Оригинальная статья на Хабре
#Android #AndroidDev #KMP
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Broadcast
NoSuchMethodError или ClassNotFoundException, знакома многим. Причина — тихий конфликт версий. Gradle по умолчанию старается брать самую новую версию из всех найденных, но срабатывает не всегда. В разных модулях одного проекта могут спокойно жить разные версии одной библиотеки (например, okhttp 4.9.0 в модуле А и 4.11.0 в модуле Б). Gradle не считает это конфликтом, потому что модули изолированы. В рантайме при передаче объекта между модулями — ClassCastException. Особенно больно это бьет в KMP, где общая бизнес-логика связывает всё в единую цепочку.Плагин
# Пример работы плагина
Version conflict detected: org.slf4j:slf4j-api
- version 2.0.17 via:
- project :app -> ch.qos.logback:logback-classic:1.4.11 -> org.slf4j:slf4j-api:2.0.17
...
- version 1.7.25 via:
- project :app -> org.apache.logging.log4j:log4j-slf4j-impl:2.17.1 -> org.slf4j:slf4j-api:1.7.25
Такая проактивная проверка помогает фиксить конфликты еще на этапе разработки и писать более стабильный код. Попробуйте.
#Gradle
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Broadcast
Данные официального бенчмарка Google
#AI #Benchmark
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Good Reads
Android CLI зацикливает на себе весь цикл разработки для андроид c агентами. Вам не нужно прыгать и искать какие скилы подтянуть в проект, какой контекст по андроид разработке предоставить. All-in-one от гугла (sdk, эмуляторы, запуск билдов ... )
Ни для чего другого, кроме как мобильной разработке, это не подходит, так что поставить точно рекомендую!
Ни для чего другого, кроме как мобильной разработке, это не подходит, так что поставить точно рекомендую!
Forwarded from Антоха Разраб про AI
This media is not supported in your browser
VIEW IN TELEGRAM
Все идет по пути к тому что у каждого тула будет CLI версия. Обсидиан запустил пару месяцев назад, а вот и Google (Пере)представляет Android CLI
По ощущениям оч кастрированный и является надстройкой над
(c) Антоха Разраб про AI
По ощущениям оч кастрированный и является надстройкой над
adb(c) Антоха Разраб про AI
Forwarded from Android Good Reads
Если вы используете Metro, в качестве DI, то знайте что оно стало стабильным. Свеженаписанный легковесный DI для android
Релиз ноутс: https://github.com/ZacSweers/metro/releases/tag/1.0.0
Релиз ноутс: https://github.com/ZacSweers/metro/releases/tag/1.0.0