От переводчика
Это мой первый перевод, поэтому прошу прощения за неточности. Если вы найдете ошибки в переводе, пожалуйста сообщите об этом. Я не нашел лучшего перевода слова сoroutine, чем сопрограмма, поэтому решил использовать оригинал. Если у вас появятся идеи по этому поводу, буду рад узнать.
Kotlin версии 1.1 принесет в язык coroutin’ы, которые позволяют приостанавливать вычисления в какой-то точке а затем продолжить их позднее. Очевидный пример этой возможности — 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: Эта статья не содержит отмены выполнений и удаления слушателей, которые могут содержать ссылки на активити. Каждый подход может иметь схожий вариант, но без утечек.
В ближайшее время появится перевод продолжения.
ссылка на оригинал статьи https://habrahabr.ru/post/314574/
Добавить комментарий