February 17, 2020

Запускаем код внутри корутин

raywenderlich.com

Для более детального освоения Корутин, необходимо ознакомиться с некоторыми базовыми концептами. К примеру узнать как запускать созданную корутину. Kotlin Coroutines API предоставляет несколько путей как именно это сделать. Для этого существуют функции называемые билдеры корутин(Coroutines builders). Это значит что если вам требуется запустить корутину, вам сперва необходимо сбилдить ее с необходимыми конфигурациями, которые подразумевает ваш use case.

После создания необходимо передать в функцию необходимые параметры(Configuration)

После этого корутину можно запустить. Для того чтобы познакомиться с некоторыми корутин билдерами давайте посмотрим на простой проект.

У нас имеется main функция с блокирующим кодом который симулирует вызов API используя для этого просто Thread.sleep(3000)

B конце выполнения возвращая объект типа User используя callback и печатает это в консоль.

Этот код блокирует main thread. Давайте попробуем обернуть вызов функции в корутину. Используем для этого GlobalScope.launch{ }. launch{ } это функция называемая корутин билдером. После просто перемещаем наш код в данный блок.

Это должно обеспечить нам то, что наша корутина будет выполнена в фоновом потоке. Но перед тем как запустить код, давайте посмотрим на то что из себя представляет функция launch{ }

Первое что можно заметить, что данная функция является Extension функцией. Вызывается она у CoroutineScope. Это значит что вы не сможете вызвать ее не имея CoroutineScope. Все это потому - что корутины как и другие функции имеют жизненный цикл. Они умеют запускаться, очищать ресурсы и завершать работу. Поэтому CoroutineScope используется для привязки к некой форме жизненного цикла. Этого в данный момент достаточно для общего понимания. Далее эта тема будет освящена шире. Следующим параметром является CoroutineContext. Этот объект представляет нечто похожее на Android context, который помогает получать доступ к необходимым ресурсам из компонентов Android.

Тем не менее в корутинах этот объект описывает как будет запущен поток относящийся к корутине, как будут отлавливаться исключения и как именно будет вести себя жизненный цикл корутины.

Последним параметром нашей функции является блок кода в который помечен как suspend. В него будет обернута наша корутина. suspend означает что наш блок может быть приостановлен в определенной точке выполнения и возвращен к работе в другой. Это также дает возможность использовать другие suspend функции внутри этого блока. Возвращаемым значением функции launch{ } будет Job. Это представление корутины в качестве объекта который вы можете отменить вызвав cancel() либо запустить если он не был запущен ранее. Объект Job крайне важен так как он представляет текущую корутину. Которую вы можете запустить/отменить, запросить состояние isActive/isCanceled или присоединить к нему другую Job'у.

Этой теории на данном этапе более чем достаточно. Давайте вернемся к коду и попробуем его запустить.

После компиляции мы видим что ничего не было выведено в консоль. Почему так произошло? Дело в том, что когда вы запускаете корутину, она не запускается моментально. Она ставится в очередь на выполнение. В данном случае это означает что она не будет выполнена до тех пор, пока не завершится программа. Это поведение можно изменить. Заставив корутину возвращать результат работы в тот момент пока программа выполняется. Для начала получим объект job из корутины.

Если вы посмотрите в документации, job.isActive будет давать true до тех пор, пока корутина не будет отменена вызовом cancel() либо пока она не завершена.

Чтобы получить результат выполнения корутины нам нужно добавить цикл while

Если вы передадите в корутину параметр CoroutineStart.LAZY корутина не будет запущена до тех пор, пока вы сами принудительно не запустите ее. Запустив такой код, вы опять получите пустую консоль. Но вызвав job.start() корутина будет выполнена полностью, а результат работы выведен на консоль.