Kotlin
Відкрити в Telegram
Подборки полезного материала по Kotlin. По всем вопросам @evgenycarter
Показати більше2 093
Підписники
Немає даних24 години
-47 днів
+330 день
Архів дописів
2 092
Яндекс обновил Yandex Mobile Ads SDK для монетизации мобильных приложений — и это интересно
Во-первых, Yandex Mobile Ads SDK 8 поддерживает Kotlin Coroutines и Swift async/await. А значит, рекламу можно загружать линейно и предсказуемо.
Во-вторых, в новой версии появился скрипт для автогенерации идентификаторов SKAdNetwork в Info.plist. Данные о конверсиях в установку теперь точнее для iOS-приложений.
В-третьих, переход на новый SDK автоматизирован. ИИ-агент анализирует код и адаптирует его под API версии 8 — на переход уходит около 15 минут.
При всех этих фичах SDK стал весить на 30% меньше для Android и на 15% — для iOS. Приложение скачивается быстрее и весит меньше — а это влияет на конверсию в установку.
Подробнее об изменения и переходе на новую версию читайте здесь.
2 092
ktorgen - Kotlin + KSP + Ktor Client Code Generator
Легкий процессор Kotlin KSP для генерации клиентского кода Ktor с аннотациями
https://github.com/kingg22/ktorgen
✍️ @kotlin_lib
2 092
🧩 Kotlin учится деструктурировать не по позиции, а по имени
В Kotlin 2.3.20 появилась экспериментальная фича name-based destructuring.
Раньше деструктуризация работала через
componentN() и зависела от порядка полей:
data class User(
val firstName: String,
val lastName: String
)
val user = User("Alice", "Husseini")
val (lastName, firstName) = user
И всё: переменные названы красиво, но значения уже перепутаны.
Теперь Kotlin предлагает другой подход - связывать переменные с property по имени, а не по позиции:
(val firstName = firstName, val lastName = lastName) = user
Это делает код безопаснее, особенно когда:
— в data class много полей
— порядок полей меняется
— деструктуризация используется в лямбдах, маппингах и UI-моделях
— имя переменной важнее позиции
Фича пока экспериментальная и включается через compiler option:
freeCompilerArgs.add("-Xname-based-destructuring=only-syntax")
Есть несколько режимов:
only-syntax - включает явный синтаксис без изменения старого поведения
name-mismatch - предупреждает, если имена не совпадают с полями
complete - делает деструктуризацию в круглых скобках name-based, а позиционную переносит в квадратные скобки:
val [firstName, lastName] = user
Похоже, Kotlin постепенно уходит от магии component1, component2 к более читаемой и безопасной деструктуризации.
Для Android-разработки это особенно приятно: меньше шансов тихо перепутать title, subtitle, id, state или другие поля в UI-моделях.
https://proandroiddev.com/beyond-positions-kotlins-new-name-based-destructuring-eee347d1bb5c
Экспериментальная фича, но направление очень здравое.
✍️ @kotlin_lib2 092
🛑 Как задушить свое приложение, используя
Dispatchers.IO
Мы привыкли думать, что Dispatchers.IO - это бездонная бочка. Закинул туда сетевой запрос или чтение файла, и корутины сами всё разрулят.
Но у Dispatchers.IO есть жесткий лимит - 64 потока (или количество ядер процессора, если их больше).
Сценарий катастрофы:
Вам нужно скачать 100 картинок или сделать батч-запросы к очень мееееедленному стороннему API. Вы запускаете 100 корутин на IO.
Первые 64 запроса занимают все доступные потоки пула и зависают в ожидании ответа от сервера (I/O block).
В этот момент пользователь нажимает кнопку "Сохранить профиль". Метод сохранения идет в локальную БД (Room/Realm), которая тоже использует Dispatchers.IO.
Результат: Запрос в БД не выполняется. Он встает в очередь и ждет, пока хотя бы одна из 64 картинок скачается и освободит системный поток. Пользователь видит бесконечный лоадер. Приложение кажется "зависшим", хотя ANR нет.
🛠 Как это лечат Джуны?
Создают свой пул: Executors.newFixedThreadPool(100).asCoroutineDispatcher().
Почему это плохо: Вы плодите тяжеловесные системные потоки в обход общего механизма корутин. Это жрет память и ломает шаринг ресурсов.
👑 Как это лечат Сеньоры?
Используют limitedParallelism. У этого метода есть две суперсилы.
Суперсила 1: Расширение лимита
// Да, этот вызов легально расширяет лимит для конкретной задачи!
val ImageDownloadDispatcher = Dispatchers.IO.limitedParallelism(100)
Документация гласит: вызов limitedParallelism на Dispatchers.IO создает независимый пул, который может превышать глобальный лимит в 64 потока, при этом используя общий elastic thread pool под капотом. Картинки будут качаться в 100 потоков, не блокируя остальные задачи на дефолтном IO.
Суперсила 2: Изоляция узких бутылочных горлышек (Bottlenecks)
Допустим, у вашей базы данных (SQLite/Room) пул коннектов равен 4.
Если вы отправите 20 корутин писать в БД на Dispatchers.IO, 4 будут писать, а 16 - тупо заблокируют потоки IO, ожидая свободного коннекта к БД.
Делаем так:
val DbDispatcher = Dispatchers.IO.limitedParallelism(4)
Теперь, если вы запустите 20 корутин на DbDispatcher, только 4 потока будут заняты. Остальные 16 корутин будут приостановлены (suspended), не блокируя системные потоки. Ваш основной IO диспетчер останется свободным для сети и файлов.
Чек-лист:
Выделяйте кастомные диспетчеры через limitedParallelism для:
1. Массовых долгих сетевых операций.
2. Работы с БД (по размеру connection pool).
3. Работы с Legacy SDK, которые не поддерживают асинхронность.
Кто из вас уже сталкивался с Thread Starvation в корутинах? Искали долго? 👇
✍️ @kotlin_lib2 092
🚀 Подборка полезных IT каналов в Max
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
Программирование Go📌
https://max.ru/golang_lib Библиотека Go (Golang) разработчика
Программирование React📌
https://max.ru/react_lib React
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии 📌
https://max.ru/progjob Вакансии в IT
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
2 092
🧨 SharedFlow для Side Effects - это ошибка. Разбираем официально лучший подход
В MVI/MVVM есть вечная проблема: разовые события (Side Effects). Показать Snackbar, перейти на другой экран, проиграть звук. Это не стейт, это событие, которое должно произойти ровно один раз.
Долгое время комьюнити пыталось решить это через SharedFlow.
Выглядело это так:
private val _effects = MutableSharedFlow<Effect>()
val effects = _effects.asSharedFlow()
Почему это выстрел в ногу?
По дефолту SharedFlow не имеет буфера (replay = 0). Если ViewModel пушит событие (_effects.emit(...)), когда UI находится в фоне (пользователь свернул приложение или открыл другой экран), у потока в этот момент нет активных подписчиков.
Результат? Событие просто дропается. Улетает в пустоту. Юзер разворачивает апп - а перехода или сообщения об ошибке нет.
Как это обычно пытаются костылить?
Начинают играться с буфером: replay = 1.
Событие перестает теряться, но появляется новая проблема: оно кэшируется! Пользователь видит ошибку, поворачивает экран, UI переподписывается на SharedFlow, считывает кэш, и старый Snackbar показывается второй раз.
✅ Как правильно? (Рекомендация Google)
Использовать Channel.
Каналы созданы именно для паттерна Producer-Consumer и имеют встроенный буфер из коробки.
class ProfileViewModel : ViewModel() {
// 1. Создаем канал
private val _effects = Channel<Effect>()
// 2. Отдаем наружу как холодный Flow
val effects = _effects.receiveAsFlow()
fun saveProfile() {
viewModelScope.launch {
repository.save()
// 3. Отправляем событие. Если UI в фоне — оно ложится в буфер.
_effects.send(Effect.ShowSnackbar("Сохранено"))
}
}
}
Почему Channel - это идеальное решение:
1. Guarantee Delivery: Если UI ушел в фон (подписчиков нет), Channel просто ставит событие в буфер ожидания.
2. Exactly-Once: Как только UI возвращается (например, Fragment снова в onStart) и делает collect, он забирает событие из очереди. Событие доставляется ровно один раз и удаляется из канала.
3. Никаких дублей: При повороте экрана новый collect просто начнет слушать пустой канал. Старое событие уже было "съедено".
Единственный нюанс: на стороне UI нужно собирать такие события правильно, учитывая жизненный цикл (например, через Lifecycle.repeatOnLifecycle или кастомные Compose-эффекты).
✍️ @kotlin_lib2 092
🚀 Подборка полезных IT каналов в Max
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии 📌
https://max.ru/progjob Вакансии в IT
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
2 092
Освой Kotlin и Android за 60 часов
Этот обширный курс по Kotlin и Android проведёт вас от основ до продвинутых концепций с практическими заданиями. В ходе курса для начинающих научит вас создавать несколько реальных приложений, включая впечатляющий клон Uber, демонстрирующий профессиональные приёмы разработки.
Курс охватывает Firestore, SQLite, MVVM, Retrofit, Navigation Component, Jetpack Compose и многое другое.
https://www.youtube.com/watch?v=blKkRoZPxLc
✍️ @kotlin_lib
2 092
🚀 Подборка полезных IT каналов в Max
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии 📌
https://max.ru/progjob Вакансии в IT
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
2 092
🐘 Ловушка MVI: Как мы превратили ViewModel в God-object
Все мы читали туториалы по MVI (Unidirectional Data Flow). Идея звучит безупречно: у вас есть один
Intent (событие от юзера), один Reducer и один State (дата-класс, описывающий весь экран).
На экране авторизации это выглядит как поэзия. Но потом вы приходите на реальный прод.
Вам дают Главный Экран приложения: здесь лента постов, фильтры, баннеры, статус сети, профиль юзера в шапке и плеер в свернутом виде.
И тут начинается MVI-ад:
data class DashboardState(
val isLoading: Boolean = false,
val feed: List<Post> = emptyList(),
val searchQuery: String = "",
val activeFilters: Set<Filter> = emptySet(),
val userProfile: Profile? = null,
val unreadNotificationsCount: Int = 0,
val miniPlayerState: PlayerState = PlayerState.Idle,
// ... и еще 20 полей
)
В чем боль такого подхода?
1. Адские copy(): Пользователь вводит текст в строку поиска. На каждый символ вы делаете _state.value = _state.value.copy(searchQuery = newText). Вы пересоздаете гигантский объект состояния ради одного символа.
2. Конфликты Reducer'ов: Разные корутины грузят профиль, ленту и нотификации. Они начинают драться за актуальный state.value, затирая copy друг друга, если не использовать update { } (а с ним код становится еще более громоздким).
3. God-object ViewModel: Ваша ViewModel разрастается до 1500 строк, потому что она вынуждена имплементить интерфейсы плеера, пагинации, аналитики и поиска.
🛠 Как это чинят Сеньоры? Декомпозиция.
Прагматичный подход гласит: Не будьте догматиками. Один экран НЕ обязан иметь ровно один StateFlow.
Паттерн 1: Раздельные потоки (State Decomposition)
Вместо одного монолитного стейта, разбейте его на логические блоки внутри одной ViewModel:
class DashboardViewModel : ViewModel() {
val searchState: StateFlow<SearchState> = ...
val feedState: StateFlow<FeedState> = ...
val playerState: StateFlow<PlayerState> = ...
}
UI (Compose или Fragment) просто подписывается на нужные куски. Ввод текста в поиск больше не триггерит пересоздание списка постов.
Паттерн 2: Компонентный подход (Множественные ViewModel)
Кто сказал, что на Fragment/Activity может быть только одна ViewModel?
Если у вас на экране есть сложный независимый блок (например, Mini Player), дайте ему свою PlayerViewModel. Пусть она живет в скоупе Activity и отвечает только за плеер. Главный экран будет чище.
MVI это паттерн, а не религия. Умейте дробить стейт, когда он начинает пахнуть.
✍️ @kotlin_lib2 092
👨💻 Вы пишете тесты, потому что «так надо»
Покрываете несколько функций, проверяете очевидные кейсы, ставите галочку. Тесты проходят, но чувствуете, что это формальность. Они не помогают находить баги, не улучшают код, не дают уверенности в изменениях.
Проблема не в тестах. Проблема в том, как вы их пишете.
🗓 12 марта в 20:00 — открытый урок «Профессиональные Unit-тесты (модульные тесты) в Android: как тесты улучшают код»
Разберём, что отличает хороший Модульный тест (unit-тест) от теста «для галочки» и почему тестируемость — это не про процент покрытия, а про архитектуру.
Что рассмотрим:
✅ как писать Модульные тесты (unit-тесты) для ViewModel, репозиториев и сценариев использования (use case'ов)
✅ как требования к тестируемости влияют на качество кода
✅ что делает тест действительно полезным
❗️ После урока вы поймёте, как тесты становятся инструментом улучшения архитектуры, а не обязательной формальностью.
Урок проходит в преддверии старта курса. Все участники получат скидку на обучение.
➡️Регистрация по ссылке : https://vk.cc/cV7L0u
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
2 092
Как нарезать Android-монолит с помощью compile-time плагинов?
Привет на связи Федотов Михаил и Абдульманов Эдуард, мы технические лидеры Android разработки в Альфа-Банке и занимаемся приложением для физических лиц.
В этой статье вспомним наш опыт разбиения большого монолитного android приложения на мини-приложения срезки, занимались мы этим уже довольно давно, но тема все равно актуальная.
Переход к таким мини-приложениям позволяет ускорить конфигурацию Gradle и уменьшить время компиляции проекта как локально так и на CI.
Думаю это будет полезно тем кто интересуется архитектурой android приложений, KSP, Dagger, а также тем у кого крупное многомодульное приложение и есть проблемы с производительностью работы Gradle в проекте.
https://habr.com/ru/companies/alfa/articles/1002998/
✍️ @kotlin_lib
2 092
👩💻 Открытый урок «Знакомство с Kotlin: пишем первый код»
🗓 5 марта в 20:00 МСК
🆓 Бесплатно. Урок в рамках старта курса «Kotlin Developer. Basic» от Otus.
Программа вебинара:
✔Разберем три ключевых преимущества Kotlin: безопасность null, лаконичность и совместимость.
✔Напишем небольшой, но полезный фрагмент, который решает понятную задачу.
✔Ответим на главный вопрос: почему Kotlin — это не просто «улучшенная Java», а другой подход к разработке.
Вебинар будет полезен:
Начинающим разработчикам, разработчикам на Java, которые хотят писать современный, более безопасный и лаконичный код.
🔗 Ссылка на регистрацию: https://vk.cc/cUZHP9
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
2 092
📉 Ваш
List убивает перформанс Compose. Разбираемся со Stability
Написали красивый экран на Compose. Данные не меняются, но Layout Inspector показывает, что ваш Composable со списком перерисовывается каждый чих. Почему?
Потому что вы передали туда обычный List.
@Composable
fun UsersList(users: List<User>) { // ❌ Компилятор вам не верит
// ...
}
В чем проблема?
Compose опирается на концепцию Stability (стабильности), чтобы понимать, можно ли «скипнуть» (пропустить) рекомпозицию узла, если параметры не изменились.
Но в Kotlin List это просто интерфейс (read-only). Под капотом туда легко может прилететь MutableList или ArrayList.
Compose не может гарантировать, что этот список кто-то не изменит из другого потока без ведома фреймворка. Поэтому компилятор помечает List как Unstable.
А если параметр Unstable - Compose всегда будет вызывать рекомпозицию этой функции, если перерисовался родитель.
Как это лечить? Есть три пути.
1. Официальный (и самый чистый): kotlinx.collections.immutable
Используем библиотеку от JetBrains. Там лежат настоящие неизменяемые коллекции.
@Composable
fun UsersList(users: ImmutableList<User>) { // ✅ Stable!
// ...
}
Компилятор Compose обучен доверять ImmutableList и PersistentList. Рекомпозиция будет скипаться.
Минус: Приходится маппить .toImmutableList() на слое ViewModel, что создает аллокации (хоть и оптимизированные).
2. Суровый (через врапперы)
Если вы не хотите тащить новую либу в проект, можно обернуть список в класс и зафорсить стабильность аннотацией:
@Immutable
@JvmInline
value class UsersState(val items: List<User>)
@Composable
fun UsersList(state: UsersState) { // ✅ Stable!
// ...
}
Мы берем ответственность на себя. Мы клянемся компилятору (через @Immutable), что не будем мутировать этот List под капотом.
3. Современный (Strong Skipping Mode)
Начиная с Compose Compiler 2.0, JetBrains включили Strong Skipping Mode по умолчанию.
Это меняет правила игры! Теперь Compose умеет скипать функции даже с Unstable параметрами (например, обычным List).
Как? Он просто сравнивает инстансы по ссылке (===). Если вы передали тот же самый объект списка, что и в прошлый раз - рекомпозиции не будет.
Но если ваша ViewModel при каждом обновлении делает uiState.copy(users = users.toList()) - инстанс меняется, и рекомпозиция всё равно ударит по UI.
Вывод: Strong Skipping Mode сильно спасает легаси-код от тормозов. Но архитектурно правильно - использовать ImmutableList. Это делает контракт вашей UI-модели железобетонным: "эти данные не мутируют".
А что в вашем проекте? Тащите kotlinx.collections.immutable, пишите врапперы или просто надеетесь на Strong Skipping? 👇
✍️ @kotlin_lib2 092
🚀 Подборка полезных IT каналов в Max
Системное администрирование, DevOps 📌
https://max.ru/i_odmin Все для системного администратора
https://max.ru/bash_srv Bash Советы
https://max.ru/sysadminof Книги для админов, полезные материалы
https://max.ru/i_odmin_book Библиотека Системного Администратора
https://max.ru/i_devops DevOps: Пишем о Docker, Kubernetes и др.
1C разработка 📌
https://max.ru/odin1c_rus Cтатьи, курсы, советы, шаблоны кода 1С
Программирование C++📌
https://max.ru/cpp_lib Библиотека C/C++ разработчика
Программирование Python 📌
https://max.ru/python_of Python академия.
https://max.ru/BookPython Библиотека Python разработчика
Java разработка 📌
https://max.ru/bookjava Библиотека Java разработчика
GitHub Сообщество 📌
https://max.ru/githublib Интересное из GitHub
Базы данных (Data Base) 📌
https://max.ru/database_info Все про базы данных
Фронтенд разработка 📌
https://max.ru/frontend_1 Подборки для frontend разработчиков
Библиотеки 📌
https://max.ru/programmist_of Книги по программированию
https://max.ru/proglb Библиотека программиста
https://max.ru/bfbook Книги для программистов
Программирование 📌
https://max.ru/bookflow Лекции, видеоуроки, доклады с IT конференций
https://max.ru/itmozg Программисты, дизайнеры, новости из мира IT
https://max.ru/php_lib Библиотека PHP программиста 👨🏼💻👩💻
Шутки программистов 📌
https://max.ru/itumor Шутки программистов
Защита, взлом, безопасность 📌
https://max.ru/thehaking Канал о кибербезопасности
https://max.ru/xakkep_1 Хакер Free
Книги, статьи для дизайнеров 📌
https://max.ru/odesigners Статьи, книги для дизайнеров
Математика 📌
https://max.ru/Pomatematike Канал по математике
https://max.ru/phismat_1 Обучающие видео, книги по Физике и Математике
Вакансии 📌
https://max.ru/progjob Вакансии в IT
Мир технологий 📌
https://max.ru/mir_teh Канал для любознательных
Бонус 📌
https://max.ru/piterspb_78 Свежие новости Санкт-Петербурга
https://max.ru/mockva_life Свежие новости Москвы
2 092
🔥 Ваш
StateFlow работает вхолостую. Разбираем SharingStarted
Превращение Flow в StateFlow через stateIn - стандартный паттерн в ViewModel. Но третий параметр (started) - это место, где утекают ресурсы процессора и сети.
Смотрим типичный код:
val uiState: StateFlow<UiState> = repository.observeData()
.map { it.toUiState() }
.stateIn(
scope = viewModelScope,
started = SharingStarted.Eagerly, // 👈 Внимание сюда
initialValue = UiState.Loading
)
1. SharingStarted.Eagerly - Режим "Зомби"
Поток запускается сразу при создании класса (ViewModel).
Даже если UI еще не готов, даже если пользователь свернул приложение, даже если экран находится в бекстеке - этот поток активен.
Он качает данные из БД, маппит их, грузит процессор.
Вердикт: Используйте только если данные нужны всегда и немедленно (например, глобальный статус сети), и их обновление дешевое.
2. SharingStarted.Lazily - Режим "Ленивец"
Поток запускается, когда появляется первый подписчик.
Проблема: когда подписчики исчезают (User свернул app), поток не останавливается. Он продолжает молотить в фоне, обновляя кэш, который никто не видит.
Вердикт: Лучше, чем Eagerly, но все еще waste of resources.
3. SharingStarted.WhileSubscribed(5000) - Выбор Сеньора 👑
Поток активен только пока есть подписчики.
Но зачем там магическое число 5000 (5 секунд)?
Сценарий: Поворот экрана (Configuration Change).
1. Activity умирает (Unsubscribe ❌).
2. Activity пересоздается (Subscribe ✅).
Между этими событиями проходит ~50-500 мс.
Если бы таймаута не было (0 мс), поток бы отменился и тут же перезапустился. Это значит:
• Лишний запрос в сеть/БД.
• Мигание UI (Loading -> Content).
Таймаут в 5 секунд дает "буферное время". Если подписчик вернулся в течение 5 секунд - поток даже не заметил разрыва. Данные остались горячими. Если не вернулся (пользователь ушел) - поток умирает и освобождает ресурсы.
⚠️ Нюанс: При использовании WhileSubscribed, если пользователь ушел с экрана на 10 минут и вернулся, поток перезапустится с нуля (re-subscribe to upstream). Убедитесь, что ваш источник данных (Repository) готов к этому (например, имеет кэш), иначе юзер увидит спиннер.
Чек-лист:
• Eagerly: почти никогда.
• Lazily: если данные нужны "навсегда" после первого открытия.
• WhileSubscribed(5000): дефолт для UI.
А вы используете константу 5000 или создаете свои стратегии? 👇
✍️ @kotlin_lib2 092
👨💻 Вы пишете адаптеры для RecyclerView и чувствуете, что делаете это не так
Когда список простой — всё понятно. Но стоит добавить разные типы элементов, свайпы или drag-and-drop, код превращается в месиво условий и костылей. Работает, но выглядит не по-профессиональному.
Разница между junior и middle — не в том, умеете ли вы делать списки. А в том, как вы это делаете.
🗓 25 февраля в 20:00 — открытый урок «Работаем со списками как профессионалы»
Разберём то, что отличает рабочий код от профессионального: разнородные элементы, ItemViewType, перетаскивание и смахивание без костылей.
Что рассмотрим:
✅как правильно работать с разными типами элементов в одном списке
✅ как реализовать drag-and-drop и swipe-to-dismiss
✅ как писать чистый, поддерживаемый код для сложных адаптеров
❗️После урока вы поймёте, как делать списки на уровне middle-разработчика. Без велосипедов, по стандартам индустрии.
Урок проходит в преддверии старта курса «Android Developer. Professional». Все участники получат скидку на обучение.
➡️ Регистрация по ссылке: https://vk.cc/cUBXoC
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
2 092
⌨️Создание AI-агентов на Kotlin
Часть 1: минимальный кодовый агент
Строить агентов - странная штука. Ты пишешь не код, который сам что-то делает. Ты пишешь код, который даёт LLM возможность что-то делать, а что именно делать - решает уже сама модель.
К этому сдвигу мышления нужно привыкнуть. Ты даёшь агенту возможность читать файлы - и он сам решает, какие файлы читать и когда. Ты ожидаешь, что он начнёт с main-файла. А он вместо этого сначала читает три тестовых файла, чтобы понять паттерны. Ты его об этом не просил. Он просто так сделал.
https://blog.jetbrains.com/ai/2025/11/building-ai-agents-in-kotlin-part-1-a-minimal-coding-agent/
Часть 2: более глубокое погружение в инструменты
В предыдущей статье мы увидели, как собрать базового coding-агента с возможностями
list, read, write и edit. Сегодня разберём, как расширять возможности агента, создавая дополнительные инструменты (tools) в рамках фреймворка Koog. В качестве примера мы сделаем ExecuteShellCommandTool - научим агента запускать код и замкнём “feedback loop”, на котором держится реальная инженерия: запускать код, наблюдать падения и улучшать код на основе реального вывода.
https://blog.jetbrains.com/ai/2025/11/building-ai-agents-in-kotlin-part-2-a-deeper-dive-into-tools/
Часть 3: под наблюдением
Две статьи позади - и наш coding-агент уже умеет немало. Он может исследовать проекты, читать и писать код, выполнять shell-команды и гонять тесты. Добавление “definition of done” (DoD) в прошлой статье дало ему нужный контур обратной связи: теперь агент итеративно улучшает решение, пока не пройдут все тесты, а не пока он сам “решит”, что закончил.
https://blog.jetbrains.com/ai/2025/12/building-ai-agents-in-kotlin-part-3-under-observation/
Часть 4: делегирование и субагенты
В прошлой части мы настроили трассировку (tracing), и это приводит к двум новым вопросам: какие эксперименты стоит проводить, опираясь на информацию, которую даёт этот инструмент? И какие части агента можно улучшить, используя его наблюдения?
https://blog.jetbrains.com/ai/2026/01/building-ai-agents-in-kotlin-part-4-delegation-and-sub-agents/
Часть 5: учим агентов забывать
Мы запускали GPT-5 Codex начиная с части 1. Он набирает 0.58 на SWE-bench Verified. Затем мы попробовали Claude Sonnet 4.5 - он показал 0.6 и работал быстрее на большинстве задач. Но на сложных задачах Claude быстрее упирался в своё контекстное окно 200K.
Скорее всего, ты тоже будешь переключать модели: ради лучшей производительности, меньшей стоимости или чтобы запускать локально. Иногда это означает более маленькие контекстные окна - особенно у локальных моделей, где “память” ограничена дорогими ресурсами. Но даже самые большие контекстные окна ломаются на сложных и длинных задачах. Нельзя просто бесконечно “покупать ещё контекста”.
https://blog.jetbrains.com/ai/2026/01/building-ai-agents-in-kotlin-part-5-teaching-agents-to-forget/
✍️ @kotlin_lib2 092
⚡️ Kotlin — современный мощный инструмент с простым синтаксисом. Он подходит как для бэкенд, так и фронтенд-разработки, к тому же на нем разрабатывают приложения под Android. Присматриваетесь к Kotlin, но еще нет навыков программирования? В OTUS стартовал набор на онлайн-курс «Kotlin Developer. Basic».
Всего через 4 месяца вы:
✔Освоите принципы программирования и алгоритмов
✔Узнаете о возможностях языка Kotlin на практике
✔Научитесь использовать популярные структуры данных
✔Опробуете Kotlin в качестве языка бэкенд- и фронтенд-разработки
И все это на живых вебинарах с ведущими разработчиками и на практике, где вы разработаете собственный проект для портфолио. Пройдите вступительный тест и успейте занять место со скидкой:
https://vk.cc/cUwBDc
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
2 092
🛡️
lifecycleScope - бро. Почему Coroutines не текут (почти)
В прошлом посте мы выяснили: Callback Hell = Memory Hell.
Вам нужно вручную отписываться в onDestroy, иначе this утечет вместе с Activity.
Kotlin Coroutines предложили решение: Structured Concurrency.
И в Android это реализовано через lifecycleScope и viewModelScope.
Как это работает на пальцах:
// Внутри Fragment / Activity
lifecycleScope.launch {
val user = api.getUser() // (1) Suspend point
showUser(user) // (2) Update UI
}
Сценарий: Пользователь открыл экран, запустилась загрузка (1), и он сразу нажал "Назад". Activity уничтожается.
Что происходит под капотом:
1. Lifecycle переходит в состояние DESTROYED.
2. lifecycleScope привязан к этому событию через LifecycleEventObserver.
3. Он вызывает cancel() у родительского Job.
4. Отмена каскадно летит вниз ко всем дочерним корутинам.
В чем магия спасения памяти?
Когда корутина отменяется в точке подвеса (suspend point, например, внутри Retrofit вызова), она выбрасывает CancellationException.
Стек вызовов сворачивается. Ссылки на локальные переменные и this (Activity) освобождаются немедленно.
Нам не нужно писать call.cancel() в onDestroy. Инфраструктура делает это за нас.
⚠️ НО! Есть подвох для Сеньоров (Cooperative Cancellation)
Отмена корутин - кооперативная. Если вы пишете вычислительный код, который не саспендится, lifecycleScope вас не спасет.
Пример утечки процессора (CPU Leak):
lifecycleScope.launch(Dispatchers.Default) {
// ❌ ЭТО НЕ ОТМЕНИТСЯ АВТОМАТИЧЕСКИ
while (true) {
heavyCalculation()
// Нет точек suspension (delay, yield, IO)
}
}
Activity умрет, Job перейдет в состояние Cancelling, но цикл продолжит крутиться в фоновом потоке, пожирая батарею, пока приложение не убьют.
Fix:
Вставляйте yield() или проверяйте isActive в тяжелых циклах.
while (isActive) { // ✅ Теперь мы проверяем флаг отмены
heavyCalculation()
}
Вывод:
lifecycleScope спасает от Memory Leaks (ссылок), но не от глупости в CPU-bound задачах.
Кто хоть раз забывал isActive в циклах и получал горячий телефон? 🔥
✍️ @kotlin_lib
Вже доступно! Дослідження Telegram за 2025 — головні інсайти року 
