- PVSM.RU - https://www.pvsm.ru -
Это мой первый перевод, поэтому прошу прощения за неточности. Если вы найдете ошибки в переводе, пожалуйста, сообщите об этом. Я не нашел лучшего перевода слова сoroutine [1], чем сопрограмма [2], поэтому решил использовать оригинал. Если у вас появятся идеи по этому поводу, буду рад узнать.
Kotlin версии 1.1 принесет в язык coroutin'ы [3], которые позволяют приостанавливать вычисления в какой-то точке, а затем продолжить их позднее. Очевидный пример этой возможности — async-await [4], который был добавлен в C# несколько лет назад.
Каждый android разработчик знает, что когда мы имеем дело с сетевыми запросами или другими I/O задачами, то нам необходимо удостовериться, что не происходит блокировка основного потока, а так же, что мы не трогаем UI из фонового потока. На протяжении многих лет приходят и уходят десятки приемов. В этой статье перечислены наиболее популярные, и показаны примеры удобства, которое несет с собой async-await.
Мы хотим получить данные пользователя Github и положить их в базу данных, а после показать результат на экране. Я не стал объяснять подходы, они скажут всё сами за себя.
Ручное управление, полный контроль
fun threads() {
val handler = Handler()
Thread {
try {
val user = githubApi.user()
userRepository.store(user)
handler.post {
threadsTV.text = "threads: [$user]"
}
} catch(e: IOException) {
handler.post {
threadsTV.text = "threads: [User retrieval failed.]"
}
}
}.start()
}
Никто же их не использует больше, верно?
fun asyncTask() {
object : AsyncTask<Unit, Unit, GithubUser?>() {
private var exception: IOException? = null
override fun doInBackground(vararg params: Unit): GithubUser? {
try {
val user = githubApi.user()
userRepository.store(user)
return user
} catch(e: IOException) {
exception = e
return null
}
}
override fun onPostExecute(user: GithubUser?) {
if (user != null) {
asyncTaskTV.text = "asyncTask: [$user]"
} else {
asyncTaskTV.text = "asyncTask: [User retrieval failed.]"
}
}
}.execute()
}
А Callback-hell кто-ниубдь использует?
fun callbacks() {
githubApi.userFromCall().enqueue(object : Callback<GithubUser> {
override fun onResponse(call: Call<GithubUser>, response: Response<GithubUser>) {
val user = response.body()
userRepository.storeCallback(user) {
callbacksTV.text = "callbacks: [$user]"
}
}
override fun onFailure(call: Call<GithubUser>, t: Throwable) {
if (t is IOException)
callbacksTV.text = "callbacks: [User retrieval failed.]"
else
throw t
}
})
}
Предоставляет крутые вещи...
fun rx() {
githubApi.userRx()
.flatMap { user ->
userRepository.storeRx(user).toSingle { user }
}
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{ user ->
rxTV.text = "rx: [$user]"
},
{ throwable ->
if (throwable is IOException)
rxTV.text = "rx: [User retrieval failed.]"
else
throw throwable
}
)
}
А как вы смотрите на это?
fun asyncAwait() = asyncUI {
try {
val user = await(githubApi.userAsync())
await(userRepository.storeAsync(user))
asyncAwaitTV.text = "asyncAwait: [$user]"
} catch(e: IOException) {
asyncAwaitTV.text = "asyncAwait: [User retrieval failed.]"
}
}
Тут asyncUI (и аналогичный async<Т>) метод включет функционал coroutin'ы, который предоставляет доступ к методу await. Каждый раз, когда выполнение достигает метода await, вычисления приостанавливаются до тех пор, пока параметр не будет вычислен, но поток, в котором произошел вызов, не блокируется. После этого coroutine продолжит свое выполнение. Метод asyncUI гарантирует, что выполнение продолжится в главном потоке.
Как вы заметили, coroutine повышает читаемость кода. Они доступны уже сейчас в версии kotlin 1.1-M02. Последний пример async-await использует библиотеку, которую я написал [5] для возможности использования coroutines на Android. Если хотите больше узнать о coroutin'ах, то можете ознакомиться с неформальным описанием [6]
PS: Эта статья не содержит отмены выполнений и удаления слушателей, которые могут содержать ссылки на активити. Каждый подход может иметь схожий вариант, но без утечек.
В ближайшее время появится перевод продолжения.
Автор: andreich
Источник [7]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/android-development/207502
Ссылки в тексте:
[1] сoroutine: https://en.wikipedia.org/wiki/Coroutine
[2] сопрограмма: https://ru.wikipedia.org/wiki/Сопрограмма
[3] coroutin'ы: https://github.com/Kotlin/kotlin-coroutines
[4] async-await: http://blog.stephencleary.com/2012/02/async-and-await.html
[5] библиотеку, которую я написал: https://github.com/nhaarman/AsyncAwait-Android
[6] неформальным описанием: https://github.com/Kotlin/kotlin-coroutines/blob/master/kotlin-coroutines-informal.md
[7] Источник: https://habrahabr.ru/post/314574/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best
Нажмите здесь для печати.