Четыре ошибки при использовании корутин и Flow

kotlin

Статья о типич­ных ошиб­ках, которые допус­кают прог­раммис­ты при работе с корути­нами. Также, в конце статьи я приведу советы Google, как исполь­зовать корути­ны.

ПО ТЕМЕ:

Ошибки при использовании корутин и Flow

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

Пред­ста­вим себе такую фун­кцию:

По фак­ту она воз­вра­щает толь­ко одно зна­чение и Flow здесь не нужен. Логич­нее было бы прев­ратить эту фун­кцию в обыч­ную suspend-фун­кцию:

Suspend-фун­кции с парамет­рами‑кол­бэками.
Suspend-фун­кции были задума­ны, что­бы заменить кол­бэки, поэто­му соз­давать фун­кции с кол­бэками в качес­тве парамет­ров — боль­шая ошиб­ка.

Возь­мем, к при­меру, сле­дующую фун­кцию:

Как в дан­ном слу­чае изба­вить­ся от кол­бэков, но оста­вить воз­можность воз­вра­тить два раз­ных типа зна­чений? Для это­го мож­но исполь­зовать sealed-клас­сы:

Ис­поль­зование GlobalScope.
Активнос­ти, фраг­менты, ViewModel, View и дру­гие стан­дар­тные клас­сы име­ют фун­кции‑рас­ширения, которые мож­но исполь­зовать для запус­ка корутин. Не сто­ит исполь­зовать GlobalScope, который может при­вес­ти к утеч­кам корутин.

Не­нуж­ное перек­лючение потоков.
Корути­ны устро­ены так, что их очень лег­ко и прос­то мож­но перек­лючить на дру­гой поток с помощью сме­ны дис­петче­ра:

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

Советы по использованию корутин

Советы Google, как исполь­зовать корути­ны.

Внед­ряй дис­петче­ры как зависи­мос­ти. Бла­года­ря это­му юнит‑тес­тирова­ние ста­нет нам­ного более удоб­ным.

Suspend-фун­кции дол­жны быть безопас­ными для вызова из UI-потока при­ложе­ния. Если suspend-фун­кция дела­ет слож­ную ресур­соем­кую работу, она дол­жна сама позабо­тить­ся о перек­лючении дис­петче­ра. Дру­гими сло­вами, за переме­щение работы в фоновый поток дол­жна отве­чать сама suspend-фун­кция, а не код, который ее вызыва­ет.

ViewModel дол­жна соз­давать корути­ны сама. Вмес­то того что­бы выс­тавлять наружу suspend-фун­кции, ViewModel дол­жна сама порож­дать корути­ны из обыч­ных фун­кций. Такой под­ход упро­щает тес­тирова­ние и не соз­дает проб­лем при пересоз­дании активнос­ти.

Не сле­дует выс­тавлять наружу изме­няемые типы дан­ных. Это стан­дар­тный при­мер гра­мот­ного ООП‑про­екти­рова­ния, который поз­волит сде­лать соп­ровож­дение кода более прос­тым.

Уров­ни дан­ных и биз­нес‑логики дол­жны быть дос­тупны через suspend-фун­кции и Flow. Сле­дова­ние это­му прин­ципу поз­волит пра­виль­но управлять жиз­ненным цик­лом при­ложе­ния, ког­да жизнью корутин управля­ет ViewModel, а не клас­сы уров­ня биз­нес‑логики.

Ис­поль­зуй TestCoroutineDispatcher. Сле­дова­ние пер­вому пра­вилу поз­волит исполь­зовать в тес­тах дис­петчер TestCoroutineDispatcher, который выпол­няет работу сра­зу, поз­воляя луч­ше кон­тро­лиро­вать исполне­ние кода.

Из­бегай исполь­зования GlobalScope. GlobalScope при­водит к утеч­кам корутин, усложня­ет тес­тирова­ние и отладку кода.
Ко­рути­ны дол­жны лег­ко уби­вать­ся. Корути­ны пос­тро­ены на идее коопе­ратив­ной мно­гоза­дач­ности. Это зна­чит, что завер­шение корути­ны через cancel() не про­исхо­дит сра­зу. Корути­на дол­жна сама про­верить свой ста­тус и завер­шить работу в слу­чае необ­ходимос­ти. В боль­шинс­тве слу­чаев делать для это­го ничего не нуж­но, так как все suspend-фун­кции из пакета kotlinx.coroutines (withContext, delay) уме­ют сами про­верять свой ста­тус и реаги­ровать на сиг­нал завер­шения. Но иног­да все‑таки при­ходит­ся делать эту работу самому:

Не забывай об исклю­чени­ях. Исклю­чения луч­ше перех­ватывать в теле корути­ны:

Источник: Best practices for coroutines in Android

Понравилась статья? Поделиться с друзьями:
Добавить комментарий