Android Broadcast
14.4K subscribers
3.64K photos
362 videos
11 files
6.04K links
Подборка новостей и статей для Android разработчиков.

Реклама и связь с автором @ab_manager

РКН https://abdev.by/rkn_tg_ab #MQRZR
Download Telegram
🏝 Как правильно подписываться на данные для UI (EN,16м)

Очень классная статья от @nek_12_personal про лучшие практики для загрузки данных из UI, чтобы не выполнять лишнюю работу и не занимать ресурсы, когда UI не показывается

Чего следует избегать
1️⃣Ранняя загрузка данных в init блоке ViewModel
Запуск загрузки данных в блоке init может привести к устаревшей информации при возвращении пользователя к экрану после длительного отсутствия.

2️⃣Ручное управление обновлением данных из UI (например, вызовом в onResume)
Такой подход может вызвать множественные параллельные запросы, что увеличивает нагрузку на систему и усложняет управление состоянием.

3️⃣Постоянное наблюдение за потоками (Flow) без учёта жизненного цикла UI
Сбор данных в viewModelScope без учёта видимости UI может привести к утечкам памяти и избыточному потреблению ресурсов.

4️⃣Инициирование загрузки данных из UI-компонентов
Перенос логики загрузки данных в UI нарушает принцип разделения ответственности и усложняет архитектуру приложения.

Все подробности в статье, которую рекомендую вам изучить подробно!

🔗 Альтернативная ссылка

#kotlin #android #coroutines
Please open Telegram to view this post
VIEW IN TELEGRAM
28👍12🤔12
🤖 Как правильно конвертировать Flow в StateFlow

Для конвертации холодного Flow в горячий StateFlow для работы с состоянием (обычно происходит в ViewModel) стоит использовать оператор Flow<T>.stateIn(), с заданием политики запуска SharingStarted.WhileSubscribed
flow..stateIn(
scope = viewModelScope,
initialValue, // задаём начальное значение
started = SharingStarted.WhileSubscribed(
stopTimeoutMillis = 5.seconds,
replayExpirationMillis = 5.seconds,
),
)


SharingStarted.WhileSubscribed() — умный способ включать сбор данных только когда есть подписчики, и автоматически останавливать его, когда они исчезают. Важно настроить несколько значений:

👉 Параметр stopTimeoutMillis - задаем какое время пройдет после того как пропадет последний подписчик чтобы остановить StateFlow. По умолчанию стоит 0 мс, но Google рекомендует выставлять 5 секунд. Это позволит не останавливать Flow при пересоздании UI при смене конфигурации или если пользователь быстро свернул/развернул приложений.

👉 Параметр replayExpirationMillis - указывает через какое время после остановки сбросить кэш значений StateFlow и начать с начала, а именно initialValue

#kotlin #coroutines
Please open Telegram to view this post
VIEW IN TELEGRAM
33👍20
🏝 Stacktrace-decoroutinator поможет вам сделать стектрейс в вызовах корутин подробнее и понятным. Работает с JVM 1.8 и выше, а также на Android 14+

Самый простой способ подключения - через Gradle плагин

#kotlin #coroutines
Please open Telegram to view this post
VIEW IN TELEGRAM
👍28
В Jetpack делают KMP API для обработки системных жестов нажатия назад или Predictive Back

Новая библиотека Jetpack NavigationEvent содержит в себе API для обработки нажатия назад или для отслеживания прогресса жеста назад. API cхоже с Dispatcher которое было сделано для Back ранее. Поддерживаются KMP таргеты: Android, Desktop/JVM, iOS, JS, Linux, WASM, watchOS, tvOS, Ming

ComponentActivity реализует интерфейс NavigationEventDispatcherOwner:
interface NavigationEventDispatcherOwner {

val navigationEventDispatcher: NavigationEventDispatcher
}


NavigationEventDispatcher представляет собой класс, для передачи системны событий Назад:
class NavigationEventDispatcher(
private val fallbackOnBackPressed: (() -> Unit)?,
private val onHasEnabledCallbacksChanged: ((Boolean) -> Unit)?,
)
// Добавления callback чтобы слушать когда произйдет нажатие "Назад"
fun addCallback(
callback: NavigationEventCallback,
priority: NavigationEventPriority = NavigationEventPriority.Default
)

fun dispatchOnStarted(event: NavigationEvent)

fun dispatchOnProgressed(event: NavigationEvent)

fun dispatchOnCompleted()

fun dispatchOnCancelled()
}


В Android Activity можно подписаться на обработку события
class MyActivity : ComponentActivity() {

init {
navigationEventDispatcher.addCallback(
callback = object : NavigationEventCallback(
isEnabled = true,
priority = NavigationEventPriority.Default
) {
override fun onEventCompleted() {
// Back сделан
}
},
priority = NavigationEventPriority.Default
)
}
}


#android #jetpack #навигация #kmp #kotlin
25👍11🔥7🤔3
🏝 Стали доступны записи доклад с KotlinConf 2025

Все сессии можно найти в расписании. Пока только на сайте, но там встроен YouTube плеер, так что позже выпустят плейлист. В @kotlin_broadcast буду выкладывать доклады и рассказывать самое интересное

#kotlin #kotlinconf
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥274
🏝 Вышел Kotlin 2.2.0

Что нового в релизе языка:
👉 Превью context parametr
👉 Non-local break и continue теперь stable
👉 Kotlin/JVM: изменения в генерации метода по умолчанию
👉 Kotlin/Native: улучшения в управлением памятью
👉 Kotlin/Wasm: wasmJs таргет отделили от js таргета
🐘 Поддержка Gradle 7.6.3 - 8.14
👉 Base64 стало Stable

#kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
40👍5🔥2
Media is too big
VIEW IN TELEGRAM
📹 Эти фичи изменят разработку на Kotlin (15 мин)

Прошла Kotlin Conf и в рамках keynote показали 3 фичи:
🏝 улучшение destructing declaration
🏝 обязательное использование возвращаемых значений для всех методов
🏝 улучшение работы с ошибками (не с exception, именно ошибками логики)

Версия на 📹 VK Video и 📺 RuTube

#AndroidBroadcast #kotlin #kotlinconf25
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥28👍145🤯1
🏝 Приоритеты поддержки таргетов JetBrains и Google выбирают на основе тиров. Особенно зоопарк в Kotlin/Native таргета (их суммарно 21 на момент написани поста). Все они поделены на три тира по важности. Tier 1 - самый важный и работы ведутся в первую очередь, а вот Tier 3 - самый низкоприоритетный и неинтересный. Там находятся все Android Native тарегты, mingwX64 и watchosDeviceArm64.

Именно по этой причине Google не фокусируется на этих таргетах, хотя mingwX64 не обходит стороной.

#kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10
🚀 Вышел Ktor 3.2.2, который исправил работу на Android и другие минорные баги

#ktor #kotlin #android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍20🔥1
🐱 Torrent Search - open source проект для поиска и скачивания с разных торрентов.

Стек: #kotlin, #material3, #compose, Ktor, Room

#android #пример
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍31🤯174🔥2🎉1🤝1
🏝 Kotlin where: Элегантное ограничение типов для чистоты и безопасности

Как часто в Android-разработке вы видели сомнительные as-приведения? 🤔

Вот пример, который недавно попался мне на глаза:

class Sample(private val activity: Activity) {

fun doSomething() {
// Опасно! Может упасть с ClassCastException,
// если activity не реализует LifecycleOwner
(activity as LifecycleOwner).lifecycle.addObserver(...)
}
}


Опустим тот факт, что здесь стоит использовать слабую ссылку (WeakReference) на Activity. Меня больше смутила необходимость вручную приводить Activity к LifecycleOwner.

Да, в современной Android-разработке AppCompatActivity и FragmentActivity реализуют этот интерфейс. Но наша цель — писать чистый и стабильный код, который не полагается на слепую веру, а гарантирует безопасность на уровне типов.

💡Решение: Ограничение типов с помощью where

В Kotlin мы можем использовать условие where для универсальных параметров, чтобы указать: «класс A должен быть одновременно и Activity, и LifecycleOwner

class Sample<A>(private val activity: A)
where A : Activity,
A : LifecycleOwner {

fun doSomething() {
// Теперь activity можно использовать как LifecycleOwner
// БЕЗОПАСНО и без приведения типов
activity.lifecycle.addObserver(...)
}
}


Этот же подход отлично работает и для функций:

fun <A> doSomethingWith(activity: A)
where A : Activity,
A : LifecycleOwner {
// Полная типобезопасность
activity.lifecycle.addObserver(...)
}


В чем выигрыш?

Безопасность: Компилятор гарантирует, что в класс Sample или функцию doSomethingWith можно передать только объект, который удовлетворяет обоим условиям:
1️⃣Исключаются ошибки ClassCastException в рантайме.
2️⃣Чистота кода: Исчезают громоздкие и опасные приведения через as.
3️⃣ Выразительность: Сигнатура класса/функции явно сообщает о своих требованиях к переданным зависимостям.

Используйте силу системы типов Kotlin на полную! Это делает код не только чище, но и стабильнее. 💪

#kotlin #android #androiddev
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍161🔥3622
🔥 Вышел JUnit 6 с поддержкой Kotlin

Прошло более 8 лет с релиза JUnit 5 (10 сентября 2017 года) и вот новая мажорная версия популярного фреймворка для написания Unit тестов в Java

Ключевые изменения в новой версии:
👉 Поддержка Java 17 и Kotlin 2.2+
👉 Переход на аннотации JSpecify
🏝 Поддержка корутин из Kotlin
👉 Поддержка Java Flight Recorder (JFR) из коробки
👉 Поддержка отмены выполнения теста
👉 Удалено deprecated API
👉 --fail-fast режим для запуска тестов из терминала

#тестирование #kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥50👍10🤯3
🏝 KSP стало независеть от версии Kotlin. Неужели API плагинов Kotlin компилятора стало стабильным? Обновляйтесь до версии KSP 2.3.0 (версии Kotlin в названии больше нету)

Также KSP1 теперь deprecated, нужно чтобы всё умело работать с новой версией.

#ksp #kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
27🔥14👍12🤯5
📹 Зачем Apple тянет Swift на Android?

Рабочая группа Swift on Android показала первую раннюю сборку Swift на Android. Я её изучил, посмотрел возможности и делюсь своими мыслями зачем они идут и смогут ли составить конкуренцию Kotlin Multiplatform

#AndroidBroadcast #kotlin #swift #apple #google #android
Please open Telegram to view this post
VIEW IN TELEGRAM
👍17🤔102🔥2
🤖 Google выпустила базовый курс по Kotlin Multiplatform для Android-разработчиков

Если вы уже уверенно пишете под Android, но хотите понять, как работает 🏝 Kotlin Multiplatform — этот курс станет отличной стартовой точкой.
Он включает теорию (видео и статьи) и практические задания 🧩

Из курса вы узнаете:
👉 Как устроена разработка с Kotlin Multiplatform
👉 Как превратить Android-проект в KMP с Android-таргетом
👉 Как использовать common- и platform-specific API
👉 Как интегрировать код в iOS-приложение
👉 Как мигрировать существующие решения на KMP

#kmp #kotlin #android #google #курс
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥78👍14🙏1
🚀 Вышел SavedState 1.4.0 — теперь с поддержкой nullable типов

Saved State — это библиотека Jetpack, которая помогает сохранять и восстанавливать состояние при пересоздании, например из-за изменений конфигурации в Android или при выгрузке процесса системой. Поддерживает Kotlin Multiplatform


Вышел androidx.savedstate:1.4.0, и в этом обновлении основное внимание уделено улучшению API. Ключевое изменение - добавлена нативная поддержка nullable типов в SavedStateRegistryOwner.saved, а также в функциях encodeToSavedState() и decodeFromSavedState() — теперь можно напрямую сохранять и восстанавливать null-значения без костылей.

// Теперь это работает корректно без дополнительных проверок.
var name: String? by savedState(saved = "name", default = null)


#android #jetpack #kotlin #kmp #jetpackupdate #androidjetpack
Please open Telegram to view this post
VIEW IN TELEGRAM
👍19🔥81
🏝 Stacktrace-decoroutinator - библиотека для восстановления стектрейса ошибок, связанных с Kotlin Coroutines. Работает с Android 14+ и Java 8 и выше

Для работы в Android надо подключить Gradle плагин
plugins {
id("dev.reformator.stacktracedecoroutinator") version "2.5.8"
}


#android #kotlin #coroutines
Please open Telegram to view this post
VIEW IN TELEGRAM
👍36🔥6🤔3
🚀 Вышла стабильная версия Jetpack DataStore 1.2

Google выпустила долгожданный стабильный релиз DataStore 1.2.0. Эта версия приносит несколько важных улучшений, которые делают библиотеку ещё более мощной и удобной, особенно для проектов, не полностью перешедших на Kotlin Coroutines.

Ключевые нововведения:

Поддержка Guava
Появился новый модуль datastore-guava, который предоставляет API на основе ListenableFuture для разработчиков, использующих Guava. Теперь подключать DataStore в проекты на Java стало намного проще (а нужно было???)

// Пример использования GuavaDataStore
val guavaDataStore: DataStore<Preferences> = GuavaDataStore.from(
produceFile = { context.preferencesDataStoreFile("settings.pb") },
serializer = PreferencesSerializer,
executor = Dispatchers.IO.asExecutor() // Используем Executor
)

ListenableFuture<Preferences> future = guavaDataStore.getData();


Мультипроцессность для GuavaDataStore
Функциональность многопроцессного доступа, ранее доступная для Kotlin-версии, теперь добавлена и в GuavaDataStore.

Поддержка Android Direct Boot - работа приложений до разблокировки устройства
DataStore теперь можно безопасно использовать в режиме Direct Boot. Для этого данные нужно разместить в защищённом хранилище устройства (Device Protected Storage).

val directBootDataStore = DataStoreFactory.createInDeviceProtectedStorage(
serializer = PreferencesSerializer
) { context.preferencesDataStoreFile("direct_boot_settings.pb") }


Исправления важных багов
👉 Устранен UnsatisifedLinkError при использовании R8 без стандартного ProGuard-файла.
👉 Исправлена проблема, из-за которой операции GuavaDataStore могли запускаться на главном потоке вместо указанного IO-диспетчера.
👉 Решена проблема с FileNotFoundException в OkioStorage при одновременном обращении к файлу (добавлена вторая попытка чтения).

Прочие улучшения
👉 Добавлен PreferencesFileSerializer — готовый сериализатор для работы с FileStorage.

#Android #Jetpack #DataStore #Kotlin #Java #Guava
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍4
🚀 Lifecycle 2.10.0 вышел в стабильной версии!

Google выпустила мажорное обновление библиотек Lifecycle. Этот релиз сфокусирован на улучшении интеграции с Compose.

⚙️ rememberLifecycleOwner для Compose
Новый композабл позволяет создавать изолированные LifecycleOwner внутри UI. Идеально для компонентов, которым нужно независимое управление состоянием — например, для HorizontalPager, где только активная страница должна быть в состоянии RESUMED.

@Composable
fun MyComposable() {
val lifecycleOwner = rememberLifecycleOwner(
maxLifecycle = Lifecycle.State.RESUMED,
parentLifecycleOwner = LocalLifecycleOwner.current,
)

CompositionLocalProvider(
LocalLifecycleOwner provides lifecycleOwner
) {
// Дочерние композаблы теперь имеют собственный жизненный цикл
}
}


🚀 Интеграция с Navigation 3
Новый артефакт lifecycle-viewmodel-navigation3 предоставляет готовый декоратор для автоматической привязки ViewModel к отдельным экранам в Navigation 3.

NavDisplay(
backStack = backStack,
entryDecorators = listOf(
rememberSaveableStateHolderNavEntryDecorator(),
rememberViewModelStoreNavEntryDecorator(), // Добавляем эту строку
),
entryProvider = entryProvider { /* ... */ }
)


Удобства для разработчиков:
👉 Идиоматичный Kotlin API для создания кастомных CreationExtras

    CreationExtras {
this[MY_CUSTOM_KEY] = "myValue"
}

👉 Метод savedStateHandle.saved() теперь нативно поддерживает nullable типы
👉 Конструкторы SavedStateHandle помечены как @VisibleForTesting

⚠️ Важное изменение
Повышение minSdk с API 21 до API 23 — убедитесь, что ваше приложение соответствует новым требованиям.

#Jetpack #Lifecycle #Compose #Navigation #ViewModel #Kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
14🔥7🤯3👍2🙏1
🚀 Navigation Event 1.0.0 — новая KMP-библиотека для обработки навигации на разных платформах

Что дает библиотека
👉 Единый кроссплатформенный API для замены разрозненных решений
👉 Централизованная система управления всей навигацией в приложении
👉 Базовый слой для будущих навигационных решений Android

Пример использования:
val myHandler = object : NavigationEventHandler<NavigationEventInfo>(
initialInfo = CurrentInfo,
isBackEnabled = true
) {
override fun onBackStarted(event: NavigationEvent) {
// Подготовка к навигации
}

override fun onBackProgressed(event: NavigationEvent) {
// Анимации на основе event.progress
}

override fun onBackCompleted() {
// Завершение навигации
}
}


👉 Готовая интеграция с Compose
val navEventState = rememberNavigationEventState(
currentInfo = CurrentInfo,
backInfo = PreviousInfo
)

NavigationBackHandler(
state = navEventState,
isBackEnabled = true,
onBackCompleted = { /* Действие при завершении */ }
)


👉 Диспетчеры могут образовывать родительско-дочерние цепочки:
// Compose
val childDispatcher = rememberNavigationEventDispatcher(
parent =
LocalNavigationEventDispatcherOwner
.current
.navigationEventDispatcher
)


👉 Нативная поддержка Predictive Back из Android
👉 Библиотека уже используется в Activity 1.12.0 как базовый слой

#Jetpack #Navigation #Compose #KMP #PredictiveBack #Kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
👍151