Статистика
Подписчики
6 221
-3день
-11неделя
-21месяц
Охват поста
454
454за 24 часа
563в среднем
Вовлечённость
7,3%
7,3%за 24 часа
13,9%в среднем
Упоминания в других каналах
Канал упомянули 206 раз в 40 каналах
Чем больше упоминаний и каналов — тем заметнее канал в своей нише.
О канале
Описание в Telegram
Практический Kotlin для Android и backend. Разбираем ошибки, корутины, архитектуру и инструменты для Middle/Senior. По вопросам сотрудничества и рекламы: ссылка скрыта Мы на бирже: ссылка скрыта
- Категории
- IT и программированиеОбразование
- Аудитория
- Смешанная аудитория
О подписчиках
Вк, телеграм
Оценки и отзывы
Формат размещения
1 400 ₽
топ 1 час · сутки в ленте · цена напрямую от автора
💎Эффективность за эти деньги
3,08 ₽
CPV · за показ
3 083,70 ₽
CPM · за 1000
Пересчитывается от формата и охвата 454/24ч
Гарантия выхода поста и возврат средств
Надёжность сделки
Время ответа админа
Обычно отвечает быстро
Размещений через Помогач
Первое размещение — за вами
Посты в канале
Kotlin Developer
Telegram · канал
LaunchedEffect: выбор ключа без лишних перезапусков
Экран показывает профиль по userId. ID сменился — загрузку нужно повторить. Изменился только callback результата — повторный запрос уже лишний. Это две разные причины изменения поведения.
Внутри composable задайте ID ключом, а актуальный callback читайте через rememberUpdatedState:
val currentOnResult by rememberUpdatedState(onResult)
LaunchedEffect(userId) {
val user = repository.load(userId)
currentOnResult(user)
}
При новом userId Compose отменит прежнюю корутину и запустит новую. Рекомпозиция с тем же ключом этого не делает. Вызов currentOnResult стоит после загрузки: callback читается, когда результат уже готов.
repository.load здесь — suspend-функция, выполняющая работу в корутине эффекта и поддерживающая отмену. Если внутри неё лишь запускается отдельный Job в другом scope, отмена эффекта не отменит этот Job автоматически.
При выходе эффекта из Composition его корутина отменяется. Поэтому LaunchedEffect(Unit) означает жизнь этого вызова в Composition, а не единственный запуск за всё время работы приложения.
Вывод: в ключах держите причины перезапуска работы. Значения, которые должны обновляться без перезапуска, передавайте через rememberUpdatedState.
#Android
315 просм.22 окт., 11:32
Тайм-аут корутины не выключает блокирующую операцию
Обернули блокирующее чтение в withTimeoutOrNull, задали сто миллисекунд, а поток занят гораздо дольше. Тайм-аут отменяет блок корутины, но сам по себе не прерывает произвольный код внутри него.
Код должен заметить отмену: через отменяемую приостановку или явную проверку. Обычный Thread.sleep на JVM не становится отменяемой операцией только потому, что находится внутри withTimeoutOrNull. Перенос на Dispatchers.IO сам по себе тоже не добавляет такой контракт.
Для блокирующего JVM-кода рассмотрите runInterruptible: он связывает отмену корутины с прерыванием потока. Это полезно, когда конкретная операция корректно поддерживает прерывание; такое свойство нельзя предполагать у любого клиента. Для сетевых запросов проверьте также собственные тайм-ауты библиотеки.
Внешний эффект не откатывается автоматически: удалённый сервер мог принять запись, даже если локальное ожидание уже прекращено. Поэтому повтор записи требует продуманной защиты от дублей.
Практический вывод: отдельно задайте срок ожидания, механизм остановки работы и правила безопасного повтора. Один тайм-аут не решает все три задачи.
#Kotlin #Coroutines #Timeout
375 просм.22 окт., 06:38
ИИ в работе: как продуктивность превратить в результат
Хотите, чтобы ИИ реально работал на бизнес? Только 30 % компаний получают от него ощутимый эффект. Узнайте, почему внедрение часто буксует — и как этого избежать.
На бесплатной видеолекции от Яндекс Практикума и Яндекс 360 разберём дорожную карту внедрения ИИ под разные роли. Поговорим, как технологии меняют рабочие задачи, почему экономия времени не всегда даёт прибыль, и как применять ИИ в HR, финансах, закупках, продажах и управлении. Плюс — подскажем, какие навыки развивать сотрудникам и как встраивать их в реальные процессы.
Эксперт: Александр Пасякин (Яндекс 360).
✨ Получите запись бесплатно.
Узнать больше
#реклама 16+
practicum.yandex.ru
О рекламодателе
337 просм.22 окт., 05:38
Semaphore(4): четыре операции одновременно, а не четыре в секунду
Импортёр обрабатывает сто файлов, но базе данных стоит отдавать не больше четырёх записей одновременно. Для этой границы подходит общий Semaphore(4), а не отдельный семафор внутри каждого обработчика.
Операция входит в защищённую область через withPermit { writeBatch() }. Если все разрешения заняты, следующая корутина приостанавливается до освобождения разрешения. Поток при этом не обязан ждать в блокирующем вызове.
Разрешение должно охватывать реальную работу. Если внутри withPermit только запустить отдельную задачу и сразу выйти, ограничение не будет описывать время жизни этой задачи. Дождитесь окончания нужной операции в той же области.
Это ограничение одновременного доступа, а не количества запросов за секунду. Четыре быстрых операции могут завершиться много раз за секунду; для RPS нужна отдельная политика ограничения частоты.
На ревью найдите владельца семафора и точные границы удержания разрешения. Параметр 4 полезен только тогда, когда все конкурирующие операции используют один экземпляр и держат разрешение до завершения работы.
#Kotlin #Coroutines #Concurrency
348 просм.22 окт., 03:34
Слово дня: моктейли.
Так называют безалкогольные коктейли. Плюс один интересный факт из моего канала «Меру знать надо». Присоединяйтесь — буду погружать вас в барное искусство.
Подписаться
#реклама
О рекламодателе
361 просм.22 окт., 02:34
Холодный Flow и повторные запросы при каждой коллекции
Профиль нужен двум потребителям. Flow сохранили в val, но API всё равно вызывается дважды. Посмотрите на минимальный фрагмент из suspend-функции:
val profile = flow { emit(api.loadProfile()) }
profile.first()
profile.first()
При успешном выполнении здесь два запроса: каждый first() заново собирает холодный flow и запускает его блок. val сохраняет объект Flow, но не результат запроса.
Если подписчикам нужен общий upstream, создайте разделённый поток один раз в репозитории или ViewModel:
val sharedProfile = profile.shareIn(
scope = scope,
started = SharingStarted.WhileSubscribed(5_000),
replay = 1
)
scope задаёт владельца работы; replay = 1 сохраняет последнее значение для новой подписки. После пяти секунд без подписчиков политика разрешает остановить upstream; при новой подписке источник может выполниться снова.
Важно: создание shareIn при каждом обращении снова создаёт отдельные разделённые потоки. А исключение upstream нужно обрабатывать до shareIn — catch только у подписчика его не поймает.
Вывод: сначала решите, нужны независимые загрузки, общая подписка или кэш с правилами обновления. shareIn решает задачу общей подписки; срок свежести данных придётся определить отдельно.
#Kotlin
447 просм.21 окт., 11:18
ensureActive: отмена внутри вычислительного цикла
Пользователь ушёл с экрана, Job отменён, а расчёт большого отчёта продолжает нагружать CPU. Если внутри цикла нет отменяемых приостановок и проверок состояния, одного вызова cancel() недостаточно: отмена корутин кооперативна.
Разбейте вычисление на порции и между ними вызывайте currentCoroutineContext().ensureActive(). При отменённом Job проверка выбросит CancellationException, и выполнение выйдет из цикла. Важно проверять контекст текущей корутины, а не случайного внешнего scope.
Размер порции — часть решения. Проверка через каждые 1024 элемента ограничивает число элементов между проверками, но не гарантирует задержку в миллисекундах: стоимость обработки элемента может различаться.
ensureActive() сама не приостанавливает выполнение и не отдаёт поток другим корутинам. Когда нужна ещё и возможность выполнить соседнюю работу, рассмотрите yield(). Отдельно проверьте, что обработчик ошибок не проглатывает исключение отмены.
Практический вывод: для CPU-цикла явно спроектируйте точки отмены и размер порций. Отмена не откатывает уже выполненные внешние действия.
#Kotlin #Coroutines #Cancellation
443 просм.21 окт., 09:22
supervisorScope: где заканчивается изоляция ошибки
Экран загружает несколько независимых блоков данных. Ошибка загрузки одного блока допустима, остальные должны закончить свою работу. Для такой границы подходит supervisorScope, но важно, где именно возникает исключение.
Сбой дочерней корутины внутри этой области сам по себе не отменяет соседние корутины. А исключение из самого блока supervisorScope отменяет область и всех её детей.
Типичная ловушка — вызвать внутри блока await() у неудачного async и выпустить исключение наружу. Теперь ошибка завершает уже сам блок, поэтому ожидаемой изоляции соседних операций не получится.
Также supervisorScope не устанавливает CoroutineExceptionHandler автоматически. Для дочернего launch продумайте обработку необработанного исключения.
На ревью отметьте границу блока и места, где ошибки превращаются в результат или проходят дальше. Сначала выберите политику отказа, затем структуру scope.
#Kotlin #Coroutines #ErrorHandling
454 просм.20 окт., 22:39
awaitAll: когда ожидание замечает ошибку
Запущены несколько вычислений с результатом Deferred. Нужно получить все значения, а при ошибке любого вычисления — прекратить ожидание общего результата.
awaitAll() возвращает список, когда завершились все вычисления, либо завершается исключением при ошибке любого из них, включая отмену. Оно замечает сбой, даже если проблемный Deferred находится в конце коллекции.
У deferreds.map { it.await() } сами вызовы ожидания идут последовательно: до исключения конкретного элемента выполнение дойдёт на его await(). При этом правила отмены родительского scope остаются важны — по одной этой строке нельзя обещать, что остальная работа продолжится после сбоя.
На ревью разделяйте два вопроса: как ожидаются результаты и как связаны задачи через Job. Выбор awaitAll задаёт контракт ожидания, а изоляцию ошибок нужно проектировать отдельно.
#Kotlin #Coroutines #Async
436 просм.20 окт., 21:20
Три тайм‑аута Ktor и зависший запрос
Установили connect timeout в секунду, а запрос всё равно ждёт сервер десятки секунд. Соединение уже создано: ограничение его установки больше не решает задачу ожидания ответа.
Пример конфигурации клиента Ktor с движком CIO; числа иллюстративные, в миллисекундах:
val client = HttpClient(CIO) {
install(HttpTimeout) {
requestTimeoutMillis = 5_000
connectTimeoutMillis = 1_000
socketTimeoutMillis = 2_000
}
}
request ограничивает HTTP-вызов от отправки запроса до получения ответа. connect — установку соединения. socket — паузу между пакетами, а не общую длительность обмена.
Если сервер регулярно присылает данные, socket timeout может не сработать, хотя ответ идёт слишком долго. Именно поэтому один socket timeout не заменяет request timeout.
Настройка в timeout { … } конкретного запроса переопределяет общую. При смене engine проверьте таблицу поддержки: например, JavaScript не поддерживает connect и socket timeout этого плагина.
Практический вывод: выбирайте бюджет под API и сценарий пользователя. Повторы запросов и несколько последовательных вызовов учитывайте отдельно — тайм-аут одного вызова не задаёт бюджет всей операции.
#Backend
474 просм.20 окт., 20:20
Mutex: почему вложенный withLock может зависнуть
Функция захватила Mutex и вызвала вспомогательную функцию, которая пытается захватить тот же объект. Внешняя функция ждёт внутреннюю, а внутренняя — освобождения блокировки.
Mutex нерекурсивный. При обычном вызове lock() без owner-токена повторный захват занятого mutex приостанавливает вызывающую корутину — даже если блокировку уже удерживает она сама. Одинаковый поток выполнения этого не меняет.
На ревью проверьте весь путь вызовов внутри withLock. Если вспомогательной функции нужна уже защищённая операция, разделите захват блокировки и работу под ней: внешний метод берёт mutex, внутренний работает по явно оговорённому контракту без повторного захвата.
Так граница критической секции остаётся видимой, а скрытое ожидание собственного освобождения не прячется в глубине вызовов.
#Kotlin #Coroutines #Concurrency
556 просм.20 окт., 09:14
Транзакции в корутинах Spring: какой механизм применяется
Сервис создаёт заказ, затем его позиции. Если второй шаг падает, первая запись не должна остаться в БД. В реактивном стеке Spring с R2DBC границу такой операции можно задать через executeAndAwait:
import org.springframework.transaction.reactive.executeAndAwait
suspend fun createOrder() =
tx.executeAndAwait {
val id = orders.insert()
items.insertFor(id)
id
}
tx — TransactionalOperator с R2dbcTransactionManager; orders и items используют Spring DatabaseClient с той же ConnectionFactory. Их suspend-методы участвуют в одной реактивной транзакции.
Ошибка должна выйти из блока, чтобы оператор выполнил rollback. Если перехватить её внутри и вернуть обычный результат, вы можете сообщить транзакционному механизму об успехе и сохранить частичный результат.
Граница применимости: этот пример относится к реактивному доступу к БД. JDBC/JPA используют другую инфраструктуру; добавление suspend не переводит её на R2DBC. Внешний HTTP-вызов тоже не откатится вместе с записями в БД.
Вывод для ревью: сначала найдите фактический transaction manager и подключения репозиториев, затем проверяйте границу транзакции и путь ошибки.
#Backend
620 просм.19 окт., 14:17
Ktor не повторяет запросы за вас
Ответ 503 ещё не означает, что HTTP-клиент попробует снова. Это ещё не баг в Ktor: по умолчанию HTTP-клиент не повторяет запросы после сетевых и серверных ошибок. Политику повторов нужно включить явно.
Пример конфигурации клиента с движком CIO:
val client = HttpClient(CIO) {
install(HttpRequestRetry) {
retryOnServerErrors(maxRetries = 2)
exponentialDelay()
}
}
Здесь повтор запускается при ответах 5xx. maxRetries = 2 — до двух повторов после исходного запроса, а не два запроса всего. exponentialDelay() задаёт растущую задержку между попытками. Эти настройки не означают повтор любого неуспешного HTTP-ответа.
Пример выше обрабатывает только ответы 5xx. Для повторов при тайм-аутах нужно отдельно настроить соответствующее условие, а HttpRequestRetry установить перед HttpTimeout.
При ревью клиента проверяйте три вещи: какие ошибки повторяем, сколько попыток допускаем и как долго ждём между ними. Просто подключить тайм-аут недостаточно: он ограничивает ожидание, но сам по себе не задаёт retry-политику.
#Kotlin #Ktor #Backend
540 просм.19 окт., 12:16
Почему CoroutineExceptionHandler не заменяет try/catch
Установили CoroutineExceptionHandler, но экран после сбоя так и не показал запасное состояние. Handler получает необработанную ошибку, когда корутина уже завершилась. Продолжить её с места падения он не может.
Если ошибка отдельной задачи не должна отменять весь блок, можно явно выбрать supervision и обработать результат через await. Фрагмент внутри suspend-функции:
supervisorScope {
val profile = async { api.loadProfile() }
try {
render(profile.await())
} catch (e: IOException) {
showOffline()
}
}
api.loadProfile() — suspend-запрос. При IOException из этой задачи await() передаст исключение в catch; запасное состояние выбирается там, где оно ещё имеет смысл. Отмена здесь не перехватывается.
Зачем supervisorScope? В обычном coroutineScope сбой дочернего async отменяет родителя. Один catch вокруг await не устраняет это распространение ошибки. Изоляцию выбирайте только для независимых задач; зависимые задачи должны отменяться вместе.
Вывод: локальный catch отвечает за ожидаемый сбой и восстановление. Handler — за необработанные ошибки на соответствующей границе Job; установленный handler не обрабатывает ошибки async вместо await.
#Kotlin
737 просм.18 окт., 12:32
StateFlow в UI: учитывать lifecycle при сборе
Во Fragment запустили collect в lifecycleScope. Экран исчез, а подписка продолжает обращаться к binding. Scope Fragment живёт до уничтожения Fragment; его View может быть уничтожена раньше.
Для обновления View запускайте сбор после её создания, например в onViewCreated, и используйте владельца lifecycle самой View:
val owner = viewLifecycleOwner
owner.lifecycleScope.launch {
owner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state ->
render(state)
}
}
}
Ниже STARTED блок сбора отменяется; при возвращении запускается заново. При уничтожении View отменяется и её scope. render здесь обновляет текущую View, а uiState — StateFlow из ViewModel.
Новая подписка получает последнее состояние. Поэтому отправка аналитики или навигация прямо из render могут повториться после возвращения на экран. Состояние лучше отображать без таких одноразовых действий.
Вывод: отдельно задавайте жизнь View, подписки и производителя. Остановка этого collect сама по себе не отменяет работу в viewModelScope: для разделённого upstream это зависит ещё и от политики sharing.
#Android
694 просм.17 окт., 19:07
📱 Gradle опять сломал сборку? А нужную библиотеку приходится искать часами?
Хорошие инструменты и решения не всегда легко найти. Особенно когда нужно было ещё вчера.
🔥 Android Developer — канал с полезными находками для Android-разработчиков.
🟢 Kotlin, Jetpack Compose и Gradle
🛠 Библиотеки, плагины и инструменты
💻 Open-source проекты с GitHub
🧠 Практические разборы и вопросы с собеседований
Меньше бесполезного поиска. Больше полезных решений.
👉 Подписывайся: https://t.me/android_dev_ru
716 просм.17 окт., 16:36
Почему нельзя проглатывать CancellationException
Пользователь закрыл экран, запрос отменился, а приложение показало «Нет сети». Частая причина — общий catch (Exception): он перехватил и CancellationException.
В корутине экрана отделите отмену от ожидаемой ошибки сети. Здесь api.loadUser() — отменяемый suspend-запрос, а render и showNetworkError обновляют UI:
try {
val user = api.loadUser()
render(user)
} catch (e: CancellationException) {
throw e
} catch (e: IOException) {
showNetworkError(e)
}
Отмена должна выйти из блока. Возврат null или Result.failure(e) из общего catch позволит следующему обычному коду выполниться: например, показать ошибку для уже закрытого экрана. Сам Job от этого снова активным не станет.
runCatching тоже ловит любой Throwable, включая отмену. Перед обработкой его неудачного результата отдельно пробрасывайте CancellationException.
Практический вывод: ловите сбои, для которых у вас есть действие. Ресурсы освобождайте в finally, а CPU-циклы без приостановок делайте отменяемыми через ensureActive().
#Kotlin
742 просм.17 окт., 01:58
inline, noinline, crossinline: выбор для HOF
Пишете inline-функцию с callback. Один параметр нужно сохранить, другой вызвать из вложенного объекта. Здесь noinline и crossinline решают разные задачи.
noinline оставляет параметр обычным объектом-функцией: его можно хранить и передавать дальше. crossinline сохраняет возможность встраивания, но запрещает нелокальный return из лямбды.
Например, вызов из вложенного Runnable требует запретить выход из внешней функции. Выбор модификатора зависит от использования параметра, а не от желания добавить «побольше inline».
• Сохраняете callback как значение — смотрите на noinline.
• Вызываете во вложенном контексте — проверьте необходимость crossinline.
#Kotlin
716 просм.16 окт., 17:05
@Immutable — обещание, не волшебная мазь
Compose считает модель нестабильной. Хочется добавить @Immutable и закрыть вопрос. Но аннотация не замораживает объект и не делает его поля неизменяемыми.
Это контракт с компилятором. Если данные меняются незаметно для Compose, неверное обещание стабильности может привести к пропущенной рекомпозиции и устаревшему интерфейсу.
Проверьте всю доступную структуру данных. val, который ссылается на изменяемую коллекцию, сам по себе не гарантирует неизменяемость. Лучше сначала исправить модель, затем выбирать аннотацию.
• Аннотация не заменяет анализ мутабельности.
• Не обещайте компилятору свойства, которых у модели нет.
807 просм.16 окт., 12:49
⚙️ ReduxKotlin — реализация Redux для Kotlin
ReduxKotlin — контейнер предсказуемого состояния для приложений Kotlin. Миссия проекта: Предоставить стандартную реализацию Redux для Kotlin.
Фичи:
🔵 Многоплатформенность. ReduxKotlin разработан с учетом приоритета многоплатформенности. Поддерживает все платформы, на которые ориентирован Kotlin (JVM, нативные приложения, JS, WASM), что позволяет совместно использовать код.
🔵 Предсказуемость. Redux помогает писать приложения, которые ведут себя согласованно и легко тестируются.
🔵 Централизация. Централизация состояния и логики вашего приложения позволяет легко обмениваться состоянием между компонентами и событиями жизненного цикла.
🔵 Портирование Redux для JavaScript. ReduxKotlin имеет тот же API, что и Redux для JavaScript. Если вы работаете с JavaScript или взаимодействуете с разработчиками JavaScript, использующими Redux, вы почувствуете себя как дома.
🖥 ReduxKotlin на GitHub
@KotlinSenior #kotlin
1 223 просм.12 окт., 13:33
❓Что такое enum класс (перечислений) в Kotlin
Если в процессе разработки возникает ситуация, когда переменная должна иметь определённые (заранее известные) значения — константы, то вместо того, чтобы плодить список констант, их все можно перечислить в классе, который был придуман специально для этого — enum (класс перечислений).
Он позволяет создать набор значений, которые могут быть использованы как единственно допустимые значения переменной. Каждая константа в классе перечислений является экземпляром этого класса и отделяется от другой константы запятой.
enum class ColorType {
RED,
BLUE,
GREEN
}
Чтобы ограничить переменную одним из значений класса перечислений, нужно назначить ей тип объявленного класса перечислений.
var color: ColorType
color = ColorType.RED
Помимо самих констант в класс перечислений можно добавить свойства и функции. Их необходимо отделять от констант точкой с запятой. Это единственное место в Kotlin, где используется точка с запятой.
enum class ColorType {
RED,
BLUE,
GREEN;
fun names() = "Красный, Голубой, Зелёный"
val rgb = "0xFFFFFF"
}
При этом каждая константа сможет обращаться к этому свойству или функции.
var color: ColorType = ColorType.RED
println(color.names()) // выведет "Красный, Голубой, Зелёный"
println(color.rgb) // выведет "0xFFFFFF"
Классы перечислений как и обычные классы также могут иметь конструктор. Так как константы являются экземплярами enum-класса, они могут быть инициализированы.
enum class Color(val rgb: Int) {
RED(0xFF0000),
GREEN(0x00FF00),
BLUE(0x0000FF)
}
Enum-константы также могут объявлять свои собственные анонимные классы как с их собственными методами, так и с перегруженными методами базового класса. Напоминаю, что при объявлении в enum-классе каких-либо членов, необходимо отделять их от объявления констант точкой с запятой.
enum class ProtocolState {
WAITING {
override fun signal() = TALKING
},
TALKING {
override fun signal() = WAITING
};
abstract fun signal(): ProtocolState
}
@KotlinSenior #kotlin
1 223 просм.9 окт., 10:54
Разработчик больше не обязан выполнять каждую задачу вручную. Но сможет ли ИИ-агент действительно помочь в работе?
ИИ-агенты уже умеют анализировать код, работать с инструментами, искать ошибки и выполнять последовательность действий. Но важно понимать, какие задачи им можно доверить, где они действительно экономят время и как сохранить контроль над результатом.
На открытом уроке 19 октября в 20:00 МСК в преддверие старта курса «Разработка ИИ-агентов» разберем, как создавать и применять агентов в реальной разработке. Вы узнаете, какие задачи можно делегировать ИИ-агентам, как они работают с кодовой базой и внешними системами, где помогают ускорить процессы, а где требуется участие разработчика.
Урок будет полезен разработчикам, техническим специалистам и тимлидам, которые хотят использовать возможности ИИ не только для генерации кода. Откройте новый подход к разработке. Регистрируйтесь на открытый урок: https://vk.cc/d2IhQt
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576
1 025 просм.8 окт., 12:11
❓ Как работают SAM-conversions
Single Abstract Method (SAM) интерфейсы — это интерфейсы только с одним абстрактным методом (функциональные интерфейсы). Kotlin поддерживает соглашение SAM — автоматическую конвертацию функций и lambda между Kotlin и Java.
SAM-conversions позволяют использовать Java-интерфейсы с единственным абстрактным методом в Kotlin, как если бы это были функциональные типы. В Kotlin вы можете использовать такие интерфейсы для создания лямбда-выражений без явного определения функционального типа.
При использовании интерфейса с единственным абстрактным методом в качестве функционального интерфейса в Java, вы можете передавать его экземпляры вместо лямбда-выражений. Это тоже возможно в Kotlin, но на самом деле Kotlin предоставляет более простой синтаксис для этого.
Когда вам нужно использовать функциональный интерфейс в Kotlin, вы можете передать lambda-выражение, которое соответствует сигнатуре единственного метода интерфейса, вместо экземпляра интерфейса. Компилятор сам преобразует лямбда-выражение в экземпляр интерфейса, используя функцию-расширение метода invoke интерфейса.
Пример:
interface OnClickListener {
fun onClick(view: View)
}
class Button {
fun setOnClickListener(listener: OnClickListener) {
// ...
}
}
val button = Button()
button.setOnClickListener { view ->
// обработка нажатия кнопки
}
В этом примере мы определяем интерфейс OnClickListener с единственным абстрактным методом onClick. Затем мы создаем класс Button, который может иметь слушатель, реализующий данный интерфейс. После этого мы создаем экземпляр Button и передаем лямбда-выражение с соответствующей сигнатурой в качестве слушателя. Компилятор автоматически преобразует это лямбда-выражение в экземпляр интерфейса OnClickListener, используя функцию-расширение invoke интерфейса.
@KotlinSenior #kotlin
966 просм.8 окт., 07:37
❓ Чем Any в Kotlin отличается от Object в Java
Any не является полным аналогом java.lang.Object.
В Object 11 методов в классе, в Any только 3 метода: equals(), hashCode() и toString(). При импорте типов Java в Kotlin все ссылки типа java.lang.Object преобразуются в Any. Поскольку Any не зависит от платформы, он объявляет только toString(), hashCode() и equals() в качестве своих членов, поэтому, чтобы сделать другие члены java.lang.Object доступными, Kotlin использует функции расширения.
Несмотря на то, что классы Object и Any имеют сходства (корневые классы иерархии классов), они также имеют и отличия, связанные с языковыми особенностями Kotlin и Java:
1️⃣ Класс Any в Kotlin является не только базовым классом для пользовательских классов, но также и супертипом для всех не-nullable типов данных, включая примитивные. В то время как в Java, класс Object является базовым классом только для пользовательских классов.
2️⃣ Класс Any в Kotlin также имеет nullable версию Any?, которая является супертипом для всех nullable типов данных в Kotlin. В то время как в Java, класс Object не имеет nullable версии.
@KotlinSenior #kotlin
960 просм.7 окт., 20:05
Vibrance — естественное смешивание цветов
Vibrance — естественное смешивание цветов для Kotlin и Compose Multiplatform. С помощью этой библиотеки вы можете смешивать (или интерполировать) цвета sRGB, как в реальных красках. Этот процесс создает другой путь между исходным и целевым цветами, имитируя субтрактивное смешивание цветов.
Фичи:
🔵 Субтрактивное смешивание цветов: интерполирует цвета sRGB, преобразуя их в скрытое цветовое пространство, представляющее концентрацию пигментов
🔵 Kotlin Multiplatform: поддержка Android, JVM, iOS, macOS, JS и Wasm
🔵 Поддержка Jetpack Compose/Compose Multiplatform: предоставляет простые в использовании API Compose, включая модификаторы и кисти для добавления градиентов, полученных методом смешивания красок: вертикальные, горизонтальные, направленные, радиальные градиенты и градиенты развертки
🖥 Vibrance на GitHub
@KotlinSenior #kotlin
894 просм.7 окт., 09:55
1 192 просм.6 окт., 10:22
💻 Fuel — очень простая библиотека Kotlin для работы с HTTP-сетями
implementation("com.github.kittinunf.fuel:fuel:3.0.0-alpha03")
Fuel поддерживает основные HTTP-методы: GET/POST/PUT/DELETE/HEAD/PATCH, поддерживает асинхронные и блокирующие запросы, а также имеет массу других возможностей
🖥 GitHub
🟡 Доки
@KotlinSenior #kotlin
784 просм.6 окт., 10:22
1 176 просм.6 окт., 10:22
774 просм.5 окт., 13:01
1 372 просм.5 окт., 13:01
⚡️⚡️Когда API недостаточно: хардкорные доклады на Mobius
Mobius — профильная конференция по мобильной разработке: здесь встречаются разработчики, архитекторы, DevOps-инженеры, тестировщики и тимлиды, чтобы разбирать технологии iOS, Android, Аврора ОС, Flutter и Kotlin Multiplatform.
📅21–22 октября, Санкт-Петербург + online
Собрали в карточках несколько докладов для тех, кому интересно заглянуть глубже готовых API и библиотек. Внутри — внутреннее устройство Kotlin Flow, NFC internals в Android, Liquid Glass и Metal, шейдеры, портирование KMP-приложения на Аврора ОС и инструмент для AI-агентов.
Это только небольшая часть программы Mobius — в ней еще десятки докладов и разные форматы для мобильных разработчиков.
Листайте карточки и переходите на сайт, чтобы посмотреть полное расписание.
🌟По промокоду KotlinSenior персональные билеты дешевле
[Купить билет]
Реклама. ООО «Джуг Ру Груп». ИНН 7801341446
716 просм.5 окт., 13:01
Посты загружаются автоматически из канала. Администрация сайта не несёт ответственности за их содержание и размещённые в них ссылки.
