Се­год­ня в выпус­ке: пра­виль­ный спо­соб сбо­ра Flow из UI-ком­понен­тов, советы, как сде­лать код на Kotlin чище, десять полез­ных лай­фха­ков и снип­петов кода на все слу­чаи жиз­ни. А так­же объ­ясне­ние сути PendingIntent и под­борка биб­лиотек для раз­работ­чиков.
 

Разработчику

 

Правильный способ сбора Flow из UI-компонентов

A safer way to collect flows from Android UIs — статья о том, как написать с исполь­зовани­ем Kotlin Flow асин­хрон­ный код, который не будет стра­дать от проб­лем перерас­хода ресур­сов.

Сов­ремен­ный под­ход к написа­нию при­ложе­ний для Android выг­лядит при­мер­но так: слой биз­нес‑логики выс­тавля­ет наружу suspend-фун­кции и про­дюсе­ры Flow, а UI-ком­понен­ты вызыва­ют suspend-фун­кции или под­писыва­ются на Flow и обновля­ют UI в соот­ветс­твии с при­шед­шими дан­ными.

Выг­лядеть это все может при­мер­но так. Фун­кция — про­дюсер обновле­ний мес­тополо­жения:

fun FusedLocationProviderClient.locationFlow() = callbackFlow<Location> {
val callback = object : LocationCallback() {
override fun onLocationResult(result: LocationResult?) {
result ?: return
try { offer(result.lastLocation) } catch(e: Exception) {}
}
}
requestLocationUpdates(createLocationRequest(), callback, Looper.getMainLooper())
.addOnFailureListener { e ->
close(e) // In case of exception, close the Flow
}
awaitClose {
removeLocationUpdates(callback)
}
}

Часть UI-ком­понен­та, под­писыва­ющаяся на Flow:

lifecycleScope.launchWhenStarted {
locationProvider.locationFlow().collect {
// Новое местоположение обновляем UI
}
}

На пер­вый взгляд — все хорошо. Бла­года­ря исполь­зованию lifecycleScope мы научи­ли код реаги­ровать на изме­нение жиз­ненно­го цик­ла при­ложе­ния — при ухо­де при­ложе­ния в фон обра­бот­ка зна­чений мес­тополо­жения будет при­оста­нов­лена. Но! Про­дюсер Flow про­дол­жит отправ­лять дан­ные об обновле­нии мес­тополо­жения.

Что­бы избе­жать такой проб­лемы, мож­но либо самос­тоятель­но запус­кать и оста­нав­ливать корути­ну — обра­бот­чик Flow при изме­нении жиз­ненно­го цик­ла при­ложе­ния, либо исполь­зовать lifecycleOwner.addRepeatingJob из биб­лиоте­ки lifecycle-runtime-ktx вер­сии 2.4.0-alpha01.

lifecycleOwner.addRepeatingJob(Lifecycle.State.STARTED) {
locationProvider.locationFlow().collect {
// Новое местоположение обновляем UI
}
}

Выг­лядит поч­ти так же, как пре­дыду­щий при­мер. Одна­ко в дан­ном слу­чае корути­на будет пол­ностью оста­нов­лена при перехо­де при­ложе­ния в любое сос­тояние, отличное от Lifecycle.State.STARTED, и запуще­на сно­ва при перехо­де в это сос­тояние. Вмес­те с ней будет оста­нов­лен и про­дюсер дан­ных о мес­тополо­жении.

То­го же эффекта мож­но добить­ся, исполь­зуя suspend-фун­кцию repeatOnLifecycle:

lifecycleScope.launch {
lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) {
locationProvider.locationFlow().collect {
// Новое местоположение обновляем UI
}
}
}

Она удоб­на в тех слу­чаях, ког­да перед сбо­ром дан­ных необ­ходимо выпол­нить опре­делен­ную работу внут­ри suspend-фун­кции.

Продолжение доступно только участникам

Вариант 1. Присоединись к сообществу «Xakep.ru», чтобы читать все материалы на сайте

Членство в сообществе в течение указанного срока откроет тебе доступ ко ВСЕМ материалам «Хакера», позволит скачивать выпуски в PDF, отключит рекламу на сайте и увеличит личную накопительную скидку! Подробнее

Вариант 2. Открой один материал

Заинтересовала статья, но нет возможности стать членом клуба «Xakep.ru»? Тогда этот вариант для тебя! Обрати внимание: этот способ подходит только для статей, опубликованных более двух месяцев назад.


  • Подпишись на наc в Telegram!

    Только важные новости и лучшие статьи

    Подписаться

  • Подписаться
    Уведомить о
    0 комментариев
    Межтекстовые Отзывы
    Посмотреть все комментарии