🤖Как обработать слишком быстрый ввод пользователя с помощью Coroutines Flow
Если внимательно посмотреть на поведение людей в поисковых полях, становится понятно:
пальцы работают быстрее, чем приложение успевает реагировать.
Пользователь печатает «a», тут же «an», следом «and» — а приложение в панике пытается перестроить результаты после каждого шага. Поток начинает «стрелять» событиями, система перегружается, а интерфейс выглядит так, будто его кто-то перематывает на ускоренной перемотке.
Главная проблема здесь не скорость человека — а то, что приложение воспринимает каждую мелочь как повод что-то пересчитать.
Чтобы интерфейс работал предсказуемо, нужно научить поток реагировать не на каждое изменение, а на осмысленное завершение ввода.
⏳Зачем нужен debounce()
Оператор debounce() работает как фильтр слишком быстрых изменений:
- быстрые изменения подряд — игнорируются
- устойчивое значение после паузы — двигаются по потоку дальше
Поток перестаёт реагировать на каждую букву и начинает слушать устойчивые состояния строки.
val results = queryFlow
.debounce(300) // значение задержки можно менять
.distinctUntilChanged()
.map { term -> searchData(term) }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), emptyList())
------------
Помимо полезных символов, пользователь может случайно добавить пробел в конце или другой невидный символ. Фактически это тот же запрос — но без обработки поиск запустится повторно.
В таких случаях можно определиться как оператор distinctUntilChanged() будет сранивать значения:
queryFlow
.debounce(300)
.distinctUntilChanged { old, new ->
old.trim() == new.trim()
}
Теперь оба состояния считаются одинаковыми, и поиск не перезапускается зря.
#kotlin#coroutines#flow#android
🐱Deepr - это open source нативное Android приложение для организации и тестирования deeplink
Стек: Kotlin, Compose, Navigation3, Arch Components, MVVM, SQLDelight, Koin, Coroutines, Fastlane
#opensource#android#deeplink#пример
🚀Вышел AndroidX WebKit 1.16.0. Забирай в работу интеграции
👉 minSdk поднят до 24 (Android 7.0) — учитывайте при апгрейде.
👉 Async-старт WebView вышел из experimental. startUpWebView вместе с ProcessGlobalConfig позволяют прогреть WebView в фоне до того как он понадобится UI. Эту штуку давно ждали в стабильной версии — для меня самое ценное обновление этого релиза.
👉 Navigation API тоже стабильный. Больше не надо @OptIn — addNavigationListener даёт колбэки на разных стадиях навигации, ошибку загрузки через Navigation.webResourceError, URL текущей страницы через Page. Главное — теперь FCP и LCP метрики прилетают напрямую из WebView без инъекции JS:
// Перед использованием проверь
// WebViewFeature.isFeatureSupported(WebViewFeature.NAVIGATION_LISTENER)
WebViewCompat.addNavigationListener(webView, object : NavigationListener {
override fun onFirstContentfulPaintMillis(page: Page, millisFromNavStart: Long) {
analytics.report("FCP", millisFromNavStart, page.url)
}
override fun onLargestContentfulPaintMillis(page: Page, millisFromNavStart: Long) {
analytics.report("LCP", millisFromNavStart, page.url)
}
override fun onNavigationCompleted(navigation: Navigation) {
navigation.webResourceError?.let { err ->
Log.w("WV", "load failed: ${err.errorCode}")
}
}
})
На один WebView можно вешать несколько листенеров и прокидывать свой Executor если нужны колбэки в фоновом потоке.
👉WebViewCompat.saveState теперь умеет ограничивать размер state. Если ловили TransactionTooLarge при сохранении состояния — это для вас.
👉 Подвезли addJavaScriptOnEvent для инъекции JS на загрузку документа и инъекцию скриптов в isolated worlds без конфликтов со страницей. Гибридным приложениям пригодится.
👉 [EXPERIMENTAL] BackForwardCacheSettings полностью переписали. Если использовали старый Builder через WebSettingsCompat.setBackForwardCacheSettings — ловите ошибку компиляции при апгрейде. Теперь так:
val settings = WebSettingsCompat.getBackForwardCacheSettings(webView.settings)
settings.setMaxPagesInCache(5)
👉Profile.setSpeculativeLoadingConfig депрекейтнут, замена через Profile.setMaxPrerenders плюс PrefetchCache.setMaxPrefetches и setPrefetchTtlSeconds (тоже experimental).
#Android#Webview#Web#AndroidDev
📹Адаптивная Android разработка сделает ваше приложение классным на любом устройстве - Google IO 2025
Очень полезный доклад про разработку адаптивного приложения по дизайну, фичам и поведению. Учитывая, стойкий тренд перехода Android разработки в KMP это как никогда актуально!
#android#adaptive#material3#jetpack#googleio
❌ Почему Android приложения банков много весят (но не всех)
Очень часто сталкиваюсь с тем, что приложения российских банков весят много (у каждого из нас конкретная цифра будет своя). При этом крупные игроки инвестируют в оптимизацию и сокращение размера.
Разберёмся, почему у нас это почти никого не волнует.
🛑 Невозможность публикации в Google Play
- Google Play был сдерживающим фактором — магазин ограничивал [максимальный размер приложения, поэтому приходилось оптимизировать.
- Отказ от App Bundle в RuStore — хотя формат и появился в магазине от VK, для его использования нужно передать сертификат подписи. Разработчики это не делают по причине "Зачем?" иди "Не доверю им свой сертификат и креды для подписи".
На август 2025 количество приложений с распространением через App Bundle в RuStore всё больше и больше.
- Распространение через универсальный APK — в нём включены все языки, архитектуры процессоров и размеры экранов. Большая часть этих ресурсов на устройстве не нужна, но всё равно хранится. Даже при обновлениях внутри приложения банки не используют Split APK хотя бы по ABI.
- Нет аналога Google Play Dynamic Delivery — этот механизм позволяет загружать только нужные пользователю ресурсы, но вне Google Play им воспользоваться невозможно.
💼По-моему мнению, главная причина: Банки не конкурируют приложениями как основным продуктом
Клиенты выбирают банк по финансовым условиям: выгодные ставки, кешбэк, бесплатное обслуживание.
Я даже не могу вспомнить рекламы банков по телевизору, где фокус на приложении, а не процентах или кэшбеке (может вы в комментариях сможете поделиться примером рекламы приложения банка)
Если завтра приложение будет весить 400 МБ вместо 200 Мб — откажется ли пользователь обновить его или вовсе пользоваться услугами банка? Скорее всего, нет. И бизнес это прекрасно понимает.
Бороться за компактность невыгодно. Это не влияет на метрики и привлечение клиентов. Люди устанавливают приложения. Деньги крутятся. Зачем заморачиваться?
Хочешь понять, как Google Play и App Bundle реально помогают ужать приложение до минимума? Разложил всё по полочкам вот в этом видео
#android#googleplay#appbundle#rustore
🤖В Android 16 добавили поддержку кодека Advanced Professional Video (APV) для записи видео профессионального уровня и пост-продакшена.
Ключевые особенности APV:
👉 Качество видео близко к raw-формату.
👉 Высокая скорость кодирования внутри кадра, удобная для редактирования.
👉 Поддержка битрейтов до нескольких Гбит/с для 2K, 4K, 8K.
👉 Фрейм-тайлинг для иммерсивного контента и параллельного кодирования.
👉 Разные форматы цветовой субдискретизации и битовой глубины.
👉 Многократное перекодирование без значительной потери качества.
👉 HDR10/10+, пользовательские метаданные, многокамерное видео.
👉 Работа с альфа-каналами, глубиной и превью.
Кодек APV реализован на основе OpenAPV, поддерживает профиль APV 422-10 с YUV 422, 10-битным кодированием и битрейтом до 2 Гбит/с. Это прорыв для профессиональной видеосъёмки на Android!
#android#android16#медиа#видеосъёмка
🚀 Вышел Jetpack Sqlite 2.5.0 с поддержкой KMP и добавлением абстракция над реализация SQLite в платформе или вовсе поставлять реализацию SQLite вместе с вашим приложением, чтобы всегда иметь самую свежую версий движка БД.
#sqlite#jetpack#android#ios#desktop
🤖Редизайн Android - Material 3 Expressive
В рамках The Android Show I/O Edition показали "самый большой редизайн Android за всё время" (со слов спикера). Нас ждет Material 3 Expressive - обновленная версия Material 3 на основе существующих токенов
Буду садиться разбираться и рассказывать на 🪙Boosty про что будет в обновлении
#android#android16#material#ui#material3expressive