Побіжний погляд на Async-Await в Android

Від перекладача
Це мій перший переклад, тому прошу вибачення за неточності. Якщо ви знайшли помилку в перекладі будь-ласка, повідомте про це. Я не знайшов кращого перекладу слова сoroutine, ніж сопрограмма, тому вирішив використовувати оригінал. Якщо у вас з'являться ідеї з цього приводу, буду радий дізнатися.
Kotlin версії 1.1 принесе в мову coroutin's, які дозволяють зупиняти обчислення в якійсь точці, а потім продовжити їх пізніше. Очевидний приклад цієї можливості — async-await, який був доданий в C# декілька років тому.
Кожен android розробник знає, що коли ми маємо справу з мережевими запитами або іншими I/O завданнями, то нам необхідно впевнитися, що не відбувається блокування основного потоку, а так само, що ми не чіпаємо UI з фонового потоку. Протягом багатьох років приходять і йдуть десятки прийомів. У цій статті перераховані найбільш популярні, і показано приклади зручності, яка несе з собою async-await.
Сценарій
Ми хочемо отримати дані користувача Github і покласти їх у базу даних, а після показати результат на екрані. Я не став пояснювати підходи, вони скажуть самі за себе.

Старий добрий Thread

Ручне управління, повний контроль
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()
}

AsyncTask андроїда

Ніхто ж їх не використовує більше, вірно?
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()
}

Callbacks

А 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
}
})
}

Rx

Надає круті речі...
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
}
)
}

Async-Await

А як ви дивитеся на це?
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 використовує бібліотеку, яку я написав для можливості використання coroutines на Android. Якщо хочете більше дізнатися про coroutin'ах, то можете ознайомитися з неформальним описом
PS: Ця стаття не містить скасування виконань і видалення слухачів, які можуть містити посилання на актівіті. Кожен підхід може мати схожий варіант, але без витоків.
найближчим часом з'явиться переклад продовження.
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.