Упростите асинхронное программирование с помощью сопрограмм Kotlin
Сопрограммы Kotlin все еще находятся на экспериментальной стадии, но они быстро становятся одной из самых популярных функций для разработчиков, которые хотят использовать методы асинхронного программирования.
Большинству мобильных приложений в какой-то момент приходится выполнять длительные или интенсивные операции, такие как сетевые вызовы или операции с базой данных. В любой момент ваше приложение может воспроизводить видео, буферизовать следующий раздел видео и отслеживать сеть на предмет возможных прерываний, при этом оставаясь реагировать на ввод пользователя.
Читать далее: я хочу разрабатывать приложения для Android – какие языки мне следует изучать?
Такая многозадачность может быть стандартным поведением для приложений Android, но реализовать его непросто. Android выполняет все свои задачи по умолчанию в одном основном потоке пользовательского интерфейса, по одной задаче за раз. Если этот поток когда-либо будет заблокирован, ваше приложение зависнет и может даже выйти из строя.
Если ваше приложение когда-либо сможет выполнять одну или несколько задач в фоновом режиме, вам придется иметь дело с несколькими потоками. Как правило, это включает в себя создание фонового потока, выполнение некоторой работы над этим потоком и отправку результатов обратно в основной поток пользовательского интерфейса Android. Однако манипулирование несколькими потоками – сложный процесс, который может быстро привести к появлению подробного кода, который сложно понять и подвержен ошибкам. Создание потока – тоже дорогостоящий процесс.
Несколько решений, таких как библиотека RxJava и AsyncTask, нацелены на упрощение многопоточности на Android, предоставляя готовые рабочие потоки. Даже с помощью сторонних библиотек и вспомогательных классов многопоточность на Android все еще остается проблемой.
Давайте взглянем на сопрограммы, экспериментальную функцию языка программирования Kotlin, которая обещает облегчить асинхронное программирование на Android. Вы можете использовать сопрограммы, чтобы быстро и легко создавать потоки, назначать работу различным потокам и выполнять длительные задачи в любом потоке (даже в основном потоке пользовательского интерфейса Android), не вызывая зависания или сбоев вашего приложения.
Зачем мне использовать сопрограммы?
Изучение любой новой технологии требует времени и усилий, поэтому, прежде чем делать решительный шаг, вы захотите узнать, что это значит для вас.
Несмотря на то, что сопрограммы по-прежнему считаются экспериментальными, есть несколько причин, по которым сопрограммы являются одной из самых обсуждаемых функций Kotlin.
Это легкая альтернатива потокам
Думайте о сопрограммах как о легкой альтернативе потокам. Вы можете запускать тысячи из них без каких-либо заметных проблем с производительностью. Здесь мы запускаем 200 000 сопрограмм и говорим им напечатать «Hello World»:
fun main(args:
Хотя приведенный выше код будет работать без каких-либо проблем, создание 200 000 потоков, скорее всего, приведет к сбою вашего приложения с ошибкой OutOfMemory .
Хотя сопрограммы обычно называют альтернативой потокам, они не обязательно заменяют их полностью. Потоки по-прежнему существуют в приложении на основе сопрограмм. Ключевое отличие состоит в том, что один поток может запускать множество сопрограмм, что помогает контролировать количество потоков вашего приложения.
Пишите код последовательно, и пусть сопрограммы сделают всю тяжелую работу!
Асинхронный код может быстро стать сложным, но сопрограммы позволяют последовательно выражать логику асинхронного кода. Просто напишите свои строки кода одну за другой, и библиотека kotlinx-coroutines-core сама определит асинхронность за вас.
Используя сопрограммы, вы можете писать асинхронный код так же просто, как если бы он выполнялся последовательно – даже когда он выполняет десятки операций в фоновом режиме.
Избегайте обратного вызова ада
Обработка выполнения асинхронного кода обычно требует некоторой формы обратного вызова. Если вы выполняете сетевой вызов, вы обычно реализуете обратные вызовы onSuccess и onFailure. По мере увеличения количества обратных вызовов ваш код становится более сложным и трудным для чтения. Многие разработчики называют эту проблему адом обратного вызова. Даже если вы имели дело с асинхронными операциями с использованием библиотеки RxJava, каждый набор вызовов RxJava обычно заканчивается несколькими обратными вызовами.
С сопрограммами вам не нужно обеспечивать обратный вызов для длительных операций. в результате получается более компактный и менее подверженный ошибкам код. Ваш код также будет легче читать и поддерживать, поскольку вам не нужно будет отслеживать обратные вызовы, чтобы выяснить, что на самом деле происходит.
Это гибкий
Сопрограммы обеспечивают гораздо большую гибкость, чем простое реактивное программирование. Они дают вам свободу писать код последовательно, когда реактивное программирование не требуется. Вы также можете написать свой код в стиле реактивного программирования, используя набор операторов Kotlin для коллекций.
Подготовка вашего проекта к сопрограмме
Android Studio 3.0 и выше поставляется в комплекте с плагином Kotlin. Чтобы создать проект, поддерживающий Kotlin, вам просто нужно установить флажок «Включить поддержку Kotlin» в мастере создания проекта Android Studio.
Этот флажок добавляет базовую поддержку Kotlin в ваш проект, но, поскольку сопрограммы в настоящее время хранятся в отдельном пакете kotlin.coroutines.experimental, вам необходимо добавить несколько дополнительных зависимостей:
dependencies {
//Add Kotlin-Coroutines-Core//
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.22.5"
//Add Kotlin-Coroutines-Android//
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.22.5"
Когда сопрограммы перестанут считаться экспериментальными, они будут перемещены в пакет kotlin.coroutines.
Хотя сопрограммы все еще имеют экспериментальный статус, использование любых функций, связанных с сопрограммами, приведет к тому, что компилятор Kotlin выдаст предупреждение. Вы можете подавить это предупреждение, открыв файл gradle.properties вашего проекта и добавив следующее:
kotlin {
experimental {
coroutines "enable"
}
}
Создание ваших первых сопрограмм
Вы можете создать сопрограмму, используя любой из следующих построителей сопрограмм:
запуск
Функция launch() – один из простейших способов создания сопрограммы, поэтому мы будем использовать этот метод в этом руководстве. Функция launch () создает новую сопрограмму и возвращает объект Job без связанного значения результата. Поскольку вы не можете вернуть значение из launch (), это примерно эквивалентно созданию нового потока с объектом Runnable.
В следующем коде мы создаем сопрограмму, инструктируем ее отложить на 10 секунд и выводим «Hello World» в Logcat Android Studio.
import
Это дает вам следующий результат:
асинхронный
Async () выполняет код внутри своего блока асинхронно и возвращает результат через Deferred , неблокирующее будущее, которое обещает предоставить результат позже. Вы можете получить результат Deferred с помощью функции await (), которая позволяет приостановить выполнение сопрограммы до завершения асинхронной операции.
Даже если вы вызовете await () в основном потоке пользовательского интерфейса, это не приведет к зависанию или сбою вашего приложения, потому что приостановлена только сопрограмма, а не весь поток (мы рассмотрим это подробнее в следующем разделе). После завершения асинхронной операции внутри async () сопрограмма возобновляется и может продолжаться в обычном режиме.
fun myAsyncCoroutine()
Здесь myMethod (result) выполняется с результатом асинхронной операции (результат, возвращаемый блоком кода внутри async) без необходимости реализации каких-либо обратных вызовов.
Замените блокировку потоков с помощью приостановки сопрограмм
Многие длительные операции, такие как сетевой ввод-вывод, требуют от вызывающей стороны блокировки до их завершения. Когда поток заблокирован, он не может делать что-либо еще, что может сделать ваше приложение вялым. В худшем случае это может даже привести к тому, что ваше приложение выдаст ошибку «Приложение не отвечает» (ANR).
Корутины вводят приостановку сопрограммы в качестве альтернативы блокировке потоков. Пока сопрограмма приостановлена, поток может продолжать делать другие вещи. Вы даже можете приостановить сопрограмму в основном потоке пользовательского интерфейса Android, при этом пользовательский интерфейс не перестанет отвечать.
Загвоздка в том, что вы можете приостановить выполнение сопрограммы только в особых точках приостановки, которые возникают, когда вы вызываете функцию приостановки. Функция приостановки может быть вызвана только из сопрограмм и других функций приостановки – если вы попытаетесь вызвать ее из своего «обычного» кода, вы столкнетесь с ошибкой компиляции.
Каждая сопрограмма должна иметь хотя бы одну функцию приостановки, которую вы передаете построителю сопрограмм. Для простоты в этой статье я буду использовать Delay () в качестве функции приостановки, которая намеренно задерживает выполнение программы на указанное время, не блокируя поток.
Давайте рассмотрим пример того, как вы можете использовать функцию приостановки Delay () для вывода «Hello world» немного другим способом. В следующем коде мы используем Delay (), чтобы приостановить выполнение сопрограммы на две секунды, а затем выводим «World». Пока сопрограмма приостановлена, поток может продолжить выполнение остальной части нашего кода.
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.coroutines.experimental.delay
import kotlinx.coroutines.experimental.launch
Конечным результатом является приложение, которое выводит «Hello» в Logcat Android Studio, ждет две секунды, а затем печатает «мир».
Помимо Delay (), библиотека kotlinx.coroutines определяет ряд функций приостановки, которые вы можете использовать в своих проектах.
Под капотом функция приостановки – это просто обычная функция, отмеченная модификатором «приостановить». В следующем примере мы создаем функцию приостановки sayWorld :
import
Переключение потоков с помощью сопрограмм
Приложения, основанные на сопрограммах, по-прежнему используют потоки, поэтому вы захотите указать, какой поток сопрограмма должна использовать для своего выполнения.
Вы можете ограничить сопрограмму основным потоком пользовательского интерфейса Android, создать новый поток или отправить сопрограмму в пул потоков, используя контекст сопрограммы, постоянный набор объектов, которые вы можете присоединить к сопрограмме. Если вы представляете сопрограммы как легкие потоки, то контекст сопрограммы подобен коллекции локальных переменных потока.
Все построители сопрограмм принимают параметр CoroutineDispatcher, который позволяет вам управлять потоком, который сопрограмма должна использовать для своего выполнения. Вы можете передать любого из следующего CoroutineDispatcher реализаций в сопрограммный строитель.
CommonPool
CommonPool контекст ограничивает сопрограмму в отдельный поток, который взят из пула общих фоновых потоков.
import
Запустите это приложение на виртуальном устройстве Android (AVD) или на физическом смартфоне или планшете Android. Затем посмотрите на Logcat Android Studio, и вы должны увидеть следующее сообщение:
I / System.out: Привет из потока ForkJoinPool.commonPool-worker-1
Если вы не укажете CoroutineDispatcher, сопрограмма будет использовать CommonPool по умолчанию. Чтобы увидеть это в действии, удалите ссылку CommonPool из своего приложения:
import
Повторно запустите этот проект, и Logcat Android Studio отобразит то же приветствие:
I / System.out: Привет из потока ForkJoinPool.commonPool-worker-1
В настоящее время, если вы хотите выполнить сопрограмму вне основного потока, вам не нужно указывать контекст, поскольку сопрограммы по умолчанию запускаются в CommonPool. Всегда есть вероятность, что поведение по умолчанию может измениться, поэтому вы все равно должны четко указывать, где вы хотите запускать сопрограмму.
newSingleThreadContext
Функция newSingleThreadContext создает поток, в котором будет выполняться сопрограмма:
import
Если вы используете newSingleThreadContext, убедитесь, что ваше приложение не потребляет ненужные ресурсы, выпуская этот поток, как только он больше не нужен.
ЛУК
Вы можете получить доступ к иерархии представлений Android только из основного потока пользовательского интерфейса. По умолчанию сопрограммы работают в CommonPool, но если вы попытаетесь изменить пользовательский интерфейс из сопрограммы, запущенной в одном из этих фоновых потоков, вы получите ошибку времени выполнения.
Чтобы запустить код в основном потоке, вам необходимо передать объект «UI» построителю сопрограмм. В следующем коде мы выполняем некоторую работу в отдельном потоке, используя запуск (CommonPool), а затем вызываем launch () для запуска другой сопрограммы, которая будет выполняться в основном потоке пользовательского интерфейса Android.
import
Проверьте вывод Android Studio Logcat, и вы должны увидеть следующее:
Отмена сопрограммы
Хотя сопрограммы могут предложить много положительных моментов, утечки памяти и сбои по-прежнему могут быть проблемой, если вы не можете остановить длительные фоновые задачи, когда связанное действие или фрагмент остановлено или уничтожено. Чтобы отменить сопрограмму, вам необходимо вызвать метод cancel () для объекта Job, возвращенного из построителя сопрограмм (job.cancel). Если вы просто хотите отменить сокращенную операцию внутри сопрограммы, вам следует вместо этого вызвать cancel () для объекта Deferred.
Подведение итогов
Вот что вам нужно знать, чтобы начать использовать сопрограммы Kotlin в своих проектах Android. Я показал вам, как создать ряд простых сопрограмм, указать поток, в котором должна выполняться каждая из этих сопрограмм, и как приостановить сопрограммы, не блокируя поток.
Читать далее:
- Введение в Kotlin для Android
- Котлин и Java: сравнение
- 10 причин попробовать Kotlin для Android
- Добавление новой функциональности с помощью функций расширения Kotlin
Как вы думаете, могут ли сопрограммы упростить асинхронное программирование в Android? У вас уже есть проверенный метод, позволяющий сделать ваши приложения многозадачными? Дайте нам знать в комментариях ниже!
Источник записи: https://www.androidauthority.com