рдпрд╣ рдХреНрдпрд╛ рд╣реИ
рдХрд┐рд╕рдиреЗ рдЕрднреА рддрдХ рдкреНрд░рд▓реЗрдЦрди рдирд╣реАрдВ рдкрдврд╝рд╛ рд╣реИ - рдореИрдВ рдЖрдкрдХреЛ рдЦреБрдж рдХреЛ рдкрд░рд┐рдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЕрддреНрдпрдзрд┐рдХ рд╕рд▓рд╛рд╣ рджреЗрддрд╛ рд╣реВрдВред
рдЬреЗрдЯрдмреНрд░реЗрди рдХреНрдпрд╛ рд▓рд┐рдЦрддрд╛ рд╣реИ:
рд▓рд╛рдЗрдмреНрд░реЗрд░реА рдХреЗ рдЕрдВрджрд░ рд╕рднреА рдЬрдЯрд┐рд▓рддрд╛рдУрдВ рдХреЛ рдЫреЛрдбрд╝рддреЗ рд╣реБрдП, рдХреЛрд░рд╛рдЙрдЯреАрди рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧ рдХреЛ рд╕рд░рд▓ рдмрдирд╛рддреЗ рд╣реИрдВред рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЗ рддрд░реНрдХ рдХреЛ рдХреЛрд░рдЯрд╛рдЗрдиреНрд╕ рдореЗрдВ рдХреНрд░рдорд┐рдХ рд░реВрдк рд╕реЗ рд╡реНрдпрдХреНрдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдЖрдзрд╛рд░ рдкреБрд╕реНрддрдХрд╛рд▓рдп рдЗрд╕реЗ рд╣рдорд╛рд░реЗ рд▓рд┐рдП рдЕрддреБрд▓реНрдпрдХрд╛рд▓рд┐рдХ рд░реВрдк рд╕реЗ рд▓рд╛рдЧреВ рдХрд░реЗрдЧрд╛ред рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕рдВрдмрдВрдзрд┐рдд рдШрдЯрдирд╛рдУрдВ рдХреА рд╕рджрд╕реНрдпрддрд╛ рд▓реЗрдиреЗ рд╡рд╛рд▓реЗ рдХреЙрд▓рдмреИрдХ рдореЗрдВ рдЙрдкрдпреЛрдЧрдХрд░реНрддрд╛ рдХреЛрдб рдХреЗ рд╕рдВрдмрдВрдзрд┐рдд рднрд╛рдЧреЛрдВ рдХреЛ рд▓рдкреЗрдЯ рд╕рдХрддрд╛ рд╣реИ, рдФрд░ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдереНрд░реЗрдб (рдпрд╛ рдпрд╣рд╛рдВ рддрдХ тАЛтАЛрдХрд┐ рдЕрд▓рдЧ-рдЕрд▓рдЧ рдорд╢реАрдиреЛрдВ рдХреЗ рд▓рд┐рдП рдирд┐рд╖реНрдкрд╛рджрди рдХреЛ рднреА рдкреНрд░реЗрд╖рдг) рдХрд░ рд╕рдХрддрд╛ рд╣реИред рдХреЛрдб рдЙрддрдирд╛ рд╣реА рд╕рд░рд▓ рд░рд╣реЗрдЧрд╛ рдЬрд┐рддрдирд╛ рдХрд┐ рд╕рдЦреНрддреА рд╕реЗ рдХреНрд░рдо рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ред
рд╕рд░рд▓ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдпрд╣ рд╕рд┐рдВрдХреНрд░реЛрдирд╕ / рдПрд╕рд┐рдВрдХреНрд░реЛрдирд╕ рдХреЛрдб рдирд┐рд╖реНрдкрд╛рджрди рдХреЗ рд▓рд┐рдП рдПрдХ рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╣реИред
рдХреНрдпреЛрдВ?
рдХреНрдпреЛрдВрдХрд┐ RxJava рдЕрдм рдлреИрд╢рди рдореЗрдВ рдирд╣реАрдВ рд╣реИ (рд╕рд┐рд░реНрдл рдордЬрд╛рдХ рдХрд░ рд░рд╣рд╛ рд╣реИ)ред
рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдореИрдВ рдХреБрдЫ рдирдпрд╛ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рдерд╛, рдФрд░ рджреВрд╕рд░реА рдмрд╛рдд, рдореИрдВ рдПрдХ рд▓реЗрдЦ - рдХреЛрд░реБрдЯрд┐рди рдХреА рдЧрддрд┐ рдФрд░ рдЕрдиреНрдп рддрд░реАрдХреЛрдВ рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдЖрдпрд╛ рдерд╛ред
рдЙрджрд╛рд╣рд░рдг
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдкреГрд╖реНрдарднреВрдорд┐ рдореЗрдВ рдПрдХ рдСрдкрд░реЗрд╢рди рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП - corutin рдкрд░ рд╣рдорд╛рд░реЗ build.gradle рдирд┐рд░реНрднрд░рддрд╛ рдореЗрдВ рдЬреЛрдбрд╝реЗрдВ:
|  | dependencies { | 
|  | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.1.1" | 
|  | implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1" | 
|  | .... | 
|  | } | 
рд╣рдо рдЕрдкрдиреЗ рдХреЛрдб рдореЗрдВ рд╡рд┐рдзрд┐ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ:
|  | suspend fun <T> withContext( | 
|  | context: CoroutineContext, | 
|  | block: suspend CoroutineScope.() -> T | 
|  | ) | 
рдЬрд╣рд╛рдВ рд╕рдВрджрд░реНрдн рдореЗрдВ - рд╣рдо рдЙрд╕ рдереНрд░реЗрдб рдкреВрд▓ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВ рдЬрд┐рд╕рдХреА рд╣рдореЗрдВ рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ - рд╕рд░рд▓ рдорд╛рдорд▓реЛрдВ рдореЗрдВ, рдпреЗ рдЖрдИрдУ, рдореБрдЦреНрдп рдФрд░ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рд╣реИрдВ
IO - рдПрдкреАрдЖрдИ рдХреЗ рд╕рд╛рде рд╕рд░рд▓ рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд▓рд┐рдП, рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рд╕рдВрдЪрд╛рд▓рди, рд╕рд╛рдЭрд╛ рдкреНрд░рд╛рдердорд┐рдХрддрд╛рдПрдВ рдЖрджрд┐ред
рдореБрдЦреНрдп - рдпреВрдЖрдИ рдзрд╛рдЧрд╛, рдЬрд╣рд╛рдВ рд╕реЗ рд╣рдо рджреГрд╢реНрдп рддрдХ рдкрд╣реБрдВрдЪ рд╕рдХрддреЗ рд╣реИрдВ
рдбрд┐рдлрд╝реЙрд▓реНрдЯ - рдЙрдЪреНрдЪ рд╕реАрдкреАрдпреВ рд▓реЛрдб рдХреЗ рд╕рд╛рде рднрд╛рд░реА рд╕рдВрдЪрд╛рд▓рди рдХреЗ рд▓рд┐рдП
(рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдФрд░ рдЕрдзрд┐рдХ)
рдмреНрд▓реЙрдХ - рд▓рд╛рдВрдмрд╛ рдЬрд┐рд╕реЗ рд╣рдо рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддреЗ рд╣реИрдВ
|  | var result = 1.0 | 
|  | withContext(IO) { | 
|  | for (i in 1..1000) { | 
|  | result += i * i | 
|  | } | 
|  | } | 
|  | Log.d("coroutines example", "result = $result") | 
рд╕рд┐рджреНрдзрд╛рдВрдд рд░реВрдк рдореЗрдВ, рдпрд╣ рд╕рдм, рд╣рдореЗрдВ 1 рд╕реЗ 1000 рддрдХ рд╡рд░реНрдЧреЛрдВ рдХреЗ рдпреЛрдЧ рдХрд╛ рдкрд░рд┐рдгрд╛рдо рдорд┐рд▓рддрд╛ рд╣реИ рдФрд░ рд╕рд╛рде рд╣реА рд╣рдо рдореБрдЦреНрдп рдзрд╛рдЧреЗ рдХреЛ рдмреНрд▓реЙрдХ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ, рдЬрд┐рд╕рдХрд╛ рдЕрд░реНрде рд╣реИ рдХрд┐ рдХреЛрдИ ANR рдирд╣реАрдВ
рд╣рд╛рд▓рд╛рдВрдХрд┐, рдЕрдЧрд░ рд╣рдорд╛рд░реА рдХреЛрд░рдЯрд╛рдЗрди рдХреЛ 20 рд╕реЗрдХрдВрдб рдХреЗ рд▓рд┐рдП рдирд┐рд╖реНрдкрд╛рджрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЗрд╕ рд╕рдордп рдХреЗ рджреМрд░рд╛рди рд╣рдордиреЗ рдбрд┐рд╡рд╛рдЗрд╕ рдХреЗ 2 рдореЛрдбрд╝ рдмрдирд╛рдП рд╣реИрдВ, рддреЛ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ 3 рдПрдХ рд╕рд╛рде рдЪрд▓рдиреЗ рд╡рд╛рд▓реЗ рдмреНрд▓реЙрдХ рд╣реЛрдВрдЧреЗред рдЙрдлрд╝ред
рдФрд░ рдЕрдЧрд░ рд╣рдордиреЗ рдмреНрд▓реЙрдХ рдореЗрдВ рдЧрддрд┐рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рдПрдХ рд▓рд┐рдВрдХ рдкрд╛рд░рд┐рдд рдХрд┐рдпрд╛ - рдПрдХ рд░рд┐рд╕рд╛рд╡ рдФрд░ рдкреБрд░рд╛рдиреЗ рдмреНрд▓реЙрдХреЛрдВ рдореЗрдВ рджреГрд╢реНрдп рдХреЗ рд╕рд╛рде рд╕рдВрдЪрд╛рд▓рди рдХрд░рдиреЗ рдХреА рдХреНрд╖рдорддрд╛ рдХреА рдХрдореАред рджреЛ рдмрд╛рд░ рдЙрдлрд╝ред
рддреЛ рдХреНрдпрд╛ рдХрд░реЗрдВ?
рдмреЗрд╣рддрд░ рдХрд░ рд░рд╣реЗ рд╣реИрдВ
|  | private var viewModelJob = Job() | 
|  | private val viewModelScope = CoroutineScope(Dispatchers.Main + viewModelJob) | 
|  |  | 
|  | fun doWork() { | 
|  | var result = 1.0 | 
|  | viewModelScope.launch { | 
|  | withContext(IO) { | 
|  | for (i in 1..1000) { | 
|  | result += i * i | 
|  | } | 
|  | } | 
|  | } | 
|  | Log.d("coroutines example", " result = $result") | 
|  | } | 
|  |  | 
|  | fun cancelJob() { | 
|  | viewModelJob.cancel() | 
|  | } | 
рдЗрд╕ рдкреНрд░рдХрд╛рд░, рд╣рдо рд╕реНрдЯреНрд░реАрдо рдореЗрдВ рдЕрдкрдиреЗ рдХреЛрдб рдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЛ рд░реЛрдХрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдереЗ, рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЬрдм рд╕реНрдХреНрд░реАрди рдХреЛ рдШреБрдорд╛рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
CoroutineScope рдиреЗ рд╕рднреА рдиреЗрд╕реНрдЯреЗрдб рдХреЙрд░рдЖрдЙрдЯреНрд╕ рдХреЗ рджрд╛рдпрд░реЗ рдХреЛ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рдмрдирд╛рдпрд╛ рдФрд░, рдЬрдм job.cancel () рдХреЛ рдХреЙрд▓ рдХрд┐рдпрд╛, рддреЛ рдЙрдирдХреЗ рдирд┐рд╖реНрдкрд╛рджрди рдХреЛ рд░реЛрдХ рджрд┐рдпрд╛ред
рдпрджрд┐ рдЖрдк рдирд┐рд╖реНрдкрд╛рджрди рдХреЛ рд░реЛрдХрдиреЗ рдХреЗ рдмрд╛рдж рдЧреБрдВрдЬрд╛рдЗрд╢ рдХрд╛ рдкреБрди: рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдпреЛрдЬрдирд╛ рдмрдирд╛рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ job.cancelChildren () рдХреЗ рдмрдЬрд╛рдп job.cancel () рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рдЯрд┐рдкреНрдкрдгреА рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж Neikist
рдЙрд╕реА рд╕рдордп, рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЕрднреА рднреА рдкреНрд░рд╡рд╛рд╣ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХрд╛ рдЕрд╡рд╕рд░ рд╣реИ:
|  | fun doWork() { | 
|  | var result = 1.0 | 
|  | var result2 = 1.0 | 
|  | viewModelScope.launch { | 
|  | withContext(IO) { | 
|  | for (i in 1..1000) { | 
|  | result += i * i | 
|  | } | 
|  | } | 
|  | withContext(Default) { | 
|  | for (i in 1..1000) { | 
|  | result2 += i * i | 
|  | } | 
|  | } | 
|  | } | 
|  | Log.d("coroutines example", "running result = $result, result 2 = $result2") | 
|  | } | 
|  |  | 
|  | fun cancelJob() { | 
|  | viewModelJob.cancel() | 
|  | } | 
рд╣рдо рд░реЗрдЯреНрд░реЛрдлрд╝рд┐рдЯ 2 рдХрдиреЗрдХреНрдЯ рдХрд░рддреЗ рд╣реИрдВ
рдУрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдирд┐рд░реНрднрд░рддрд╛ рдЬреЛрдбрд╝реЗрдВ:
|  |  | 
|  | dependencies { | 
|  | implementation "com.squareup.retrofit2:retrofit:$retrofitVersion" | 
|  | implementation "com.squareup.retrofit2:converter-moshi:$converterMoshiVersion" | 
|  | implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:$retrofitCoroutinesVersion" | 
|  | ... | 
|  | } | 
рд╣рдо рдПрдХ рдЙрджрд╛рд╣рд░рдг рдХреЗ рд░реВрдк рдореЗрдВ рдХрд▓рдо рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВ https://my-json-server.typicode.com/typicode/demo/posts
рд╣рдо рд░реЗрдЯреНрд░реЛрдлрд┐рдЯ рдЗрдВрдЯрд░рдлрд╝реЗрд╕ рдХрд╛ рд╡рд░реНрдгрди рдХрд░рддреЗ рд╣реИрдВ:
|  | interface RetrofitPosts { | 
|  |  | 
|  | @GET("posts") | 
|  | fun getPosts(): Deferred<Response<List<Post>>> | 
|  |  | 
|  | } | 
рд▓реМрдЯреЗ рдкреЛрд╕реНрдЯ рдореЙрдбрд▓ рдХрд╛ рд╡рд░реНрдгрди рдХрд░реЗрдВ:
|  | data class Post(val id: Int, val title: String) | 
рд╣рдорд╛рд░рд╛ рдмреЗрд╕рд░реЗрдкреЛрд╕рд┐рдЯрд░реА:
|  | abstract class BaseRepository<Params, Result> { | 
|  |  | 
|  | abstract suspend fun doWork(params: Params): Result | 
|  |  | 
|  | } | 
PostRepository рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди:
|  | class PostsRepository : | 
|  | BaseRepository<PostsRepository.Params, PostsRepository.Result>() { | 
|  |  | 
|  | override suspend fun doWork(params: Params): Result { | 
|  | val retrofitPosts = Retrofit | 
|  | .Builder() | 
|  | .baseUrl("https://jsonplaceholder.typicode.com") | 
|  | .addConverterFactory(MoshiConverterFactory.create()) | 
|  | .addCallAdapterFactory(CoroutineCallAdapterFactory()) | 
|  | .build() | 
|  | .create(RetrofitPosts::class.java) | 
|  | val result = retrofitPosts | 
|  | .getPosts() | 
|  | .await() | 
|  |  | 
|  | return Result(result.body()) | 
|  | } | 
|  |  | 
|  | class Params | 
|  | data class Result(val posts: List<Post>?) | 
|  | } | 
рд╣рдорд╛рд░рд╛ рдмреЗрд╕рдЙрд╕реЗрдХреЗрд╕:
|  | abstract class BaseUseCase<Params, Result> { | 
|  |  | 
|  | abstract suspend fun doWork(params: Params): Result | 
|  |  | 
|  | } | 
GetPostsListUseCase рдХрд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди:
|  | class GetListOfPostsUseCase | 
|  | : BaseUseCase<GetListOfPostsUseCase.Params, GetListOfPostsUseCase.Result>() { | 
|  |  | 
|  | override suspend fun doWork(params: Params): Result { | 
|  | return Result( | 
|  | PostsRepository() | 
|  | .doWork(PostsRepository.Params()) | 
|  | .response | 
|  | .posts | 
|  | ) | 
|  | } | 
|  |  | 
|  | class Params | 
|  | class Result(val posts: List<Post>?) | 
|  | } | 
рдпрд╣рд╛рдБ рдкрд░рд┐рдгрд╛рдо рд╣реИ:
|  | fun doWork() { | 
|  | val useCase = GetListOfPostsUseCase() | 
|  | viewModelScope.launch { | 
|  | withContext(Dispatchers.IO) { | 
|  |  | 
|  | val result = useCase.doWork( | 
|  | GetListOfPostsUseCase.Params() | 
|  | ) | 
|  | Log.d("coroutines example", "get list of posts = ${result.posts}") | 
|  | } | 
|  | } | 
|  |  | 
|  | } | 
|  |  | 
|  | fun cancelJob() { | 
|  | viewModelJob.cancel() | 
|  | } | 
рдЗрд╕реЗ рдмреЗрд╣рддрд░ рдмрдирд╛рдирд╛
рдореИрдВ рдПрдХ рдЖрд▓рд╕реА рдкреНрд░рд╛рдгреА рд╣реВрдВ рдФрд░ рд╣рд░ рдмрд╛рд░ рдЬрдм рдореИрдВ рдХреЛрдб рдХреА рдкреВрд░реА рд╢реАрдЯ рдХреЛ рдмрд╛рд╣рд░ рдирд╣реАрдВ рдирд┐рдХрд╛рд▓рдирд╛ рдЪрд╛рд╣рддрд╛, рддреЛ рдореИрдВрдиреЗ BaseViewModel рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рддрд░реАрдХреЗ рдмрдирд╛рдП:
|  | abstract class BaseViewModel : ViewModel() { | 
|  |  | 
|  | private var viewModelJob = Job() | 
|  | private val viewModelScope = CoroutineScope(Dispatchers.Main + viewModelJob) | 
|  | private var isActive = true | 
|  |  | 
|  | // Do work in IO | 
|  | fun <P> doWork(doOnAsyncBlock: suspend CoroutineScope.() -> P) { | 
|  | doCoroutineWork(doOnAsyncBlock, viewModelScope, IO) | 
|  | } | 
|  |  | 
|  | // Do work in Main | 
|  | // doWorkInMainThread {...} | 
|  | fun <P> doWorkInMainThread(doOnAsyncBlock: suspend CoroutineScope.() -> P) { | 
|  | doCoroutineWork(doOnAsyncBlock, viewModelScope, Main) | 
|  | } | 
|  |  | 
|  | // Do work in IO repeately | 
|  | // doRepeatWork(1000) {...} | 
|  | // then we need to stop it calling stopRepeatWork() | 
|  | fun <P> doRepeatWork(delay: Long, doOnAsyncBlock: suspend CoroutineScope.() -> P) { | 
|  | isActive = true | 
|  | viewModelScope.launch { | 
|  | while (this@BaseViewModel.isActive) { | 
|  | withContext(IO) { | 
|  | doOnAsyncBlock.invoke(this) | 
|  | } | 
|  | if (this@BaseViewModel.isActive) { | 
|  | delay(delay) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | fun stopRepeatWork() { | 
|  | isActive = false | 
|  | } | 
|  |  | 
|  | override fun onCleared() { | 
|  | super.onCleared() | 
|  | isActive = false | 
|  | viewModelJob.cancel() | 
|  | } | 
|  |  | 
|  | private inline fun <P> doCoroutineWork( | 
|  | crossinline doOnAsyncBlock: suspend CoroutineScope.() -> P, | 
|  | coroutineScope: CoroutineScope, | 
|  | context: CoroutineContext | 
|  | ) { | 
|  | coroutineScope.launch { | 
|  | withContext(context) { | 
|  | doOnAsyncBlock.invoke(this) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
рдЕрдм рдбрд╛рдХ рд╕реВрдЪреА рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:
|  | class PostViewModel : BaseViewModel() { | 
|  |  | 
|  | val lengthOfPostsList = MutableLiveData<String>() | 
|  |  | 
|  | fun getListOfPosts() { | 
|  | doWork { | 
|  | val result = GetListOfPostsUseCase() | 
|  | .doWork(GetListOfPostsUseCase.Params()) | 
|  | Log.d("coroutines example", "get list of posts = ${result.posts}") | 
|  | lengthOfPostsList.postValue(result.posts?.size.toString()) | 
|  | } | 
|  | } | 
рдирд┐рд╖реНрдХрд░реНрд╖
рдореИрдВрдиреЗ рдЙрддреНрдкрд╛рджреЛрдВ рдореЗрдВ рдХреЛрд░рд╛рдЙрдЯрд╛рдЗрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдФрд░ рдХреЛрдб рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ рдХреНрд▓реАрдирд░ рдФрд░ рдЕрдзрд┐рдХ рдкрдардиреАрдп рдирд┐рдХрд▓рд╛ред
рдпреБрдкреАрдбреА:
рд░реЗрдЯреНрд░реЛрдлрд╝рд┐рдЯ рдЕрдкрд╡рд╛рдж рд╣реИрдВрдбрд▓рд┐рдВрдЧ рд╡рд┐рд╡рд░рдг рдЯрд┐рдкреНрдкрдгреА рджреЗрдЦреЗрдВ