Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Kotlin Coroutines and Flow.

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers. →

Kotlin Coroutines and Flow.

코틀린 코루틴과 플로우에 대한 설명을 포함

Avatar for TaeHwan

TaeHwan

July 26, 2021

More Decks by TaeHwan

Other Decks in Programming

Transcript

  1. য়ט ঌইࠅ ղਊ • ࢎਊߨ਷ ݒ਋ рױ೤פ׮. • ࢎਊߨࠁױ ղࠗ

    ௏٘ܳ ా೧ ௏ܖ౯ਸ ઑӘ ؊ ࢓ಝࠇפ׮. • ҃೷࢚ ԙ ঌইفݶ જਸ ղਊਸ ୶о೤פ׮.
  2. Subroutine • In computer programming, a subroutine is a sequence

    of program instructions that performs a speci fi c task, packaged as a unit • In di ff erent programming languages, a subroutine may be called a procedure, a function, a routine, a method, or a subprogram. The generic term callable unit is sometimes used.
  3. Coroutines • According to Donald Knuth, Melvin Conway coined the

    term coroutine in 1958 when he applied it to construction of an assembly program. • The fi rst published explanation of the coroutine appeared later, in 1963
  4. Coroutines • Coroutines are computer-program components that generalize subroutines for

    non-preemptive multitasking, by allowing multiple entry points for suspending and resuming execution at certain locations. • Coroutines are well-suited for implementing familiar program components such as cooperative tasks, exceptions, event loops, iterators, in fi nite lists and pipes. ୹୊ : https://en.wikipedia.org/wiki/Coroutine
  5. Coroutines Run routine fun Int.sum() Loop fun Int.sum() Loop fun

    Int.sum() Loop fun Int.sum() Loop 10.sum() . . . Entry point ৈ۞ ѐ ೲਊ
  6. Kotlin Coroutines • Asynchronous or non-blocking programming is an important

    part of the development landscape. When creating server-side, desktop, or mobile applications, it's important to provide an experience that is not only fl uid from the user's perspective, but also scalable when needed. • Kotlin solves this problem in a fl exible way by providing coroutine support at the language level and delegating most of the functionality to libraries. • In addition to opening the doors to asynchronous programming, coroutines also provide a wealth of other possibilities, such as concurrency and actors.
  7. Kotlin Coroutines Default : dependencies { implementation(“org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1”) } Android :

    dependencies { implementation(“org.jetbrains.kotlinx:kotlinx-coroutines-android:1.5.1”) } repository { mavenCentral() } Androidীࢲח dependencies ࢎਊ द coroutines-androidܳ ӝࠄਵ۽ ഝਊೞݶ ؾפ׮. উ٘۽੉٘৬ ޖҙೠ ݽٕ۽ ഝਊೡ Ѫ੉ۄݶ coroutines-coreܳ ഝਊೞݶ ؾפ׮.
  8. Kotlin Coroutines class MainViewModel : ViewModel() { init { viewModelScope.launch(Dispatchers.IO)

    { Log.i("TEMP", getMessage()) } Log.i("TEMP", "Hello") } private suspend fun getMessage(): String { delay(1_000L) return "World!" } } AAC-ViewModelਸ ഝਊೡ ҃਋੄ ௏ܖ౯ ࢎਊߨ੉ݴ, launch ز੘द ࢎਊೡ ӝࠄ झா઴۞ܳ Dispatchersਸ IO۽ ߸҃೤פ׮.
  9. Kotlin Coroutines public val ViewModel.viewModelScope: CoroutineScope get() { val scope:

    CoroutineScope? = this.getTag(JOB_KEY) if (scope != null) { return scope } return setTagIfAbsent( JOB_KEY, CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) ) } internal class CloseableCoroutineScope(context: CoroutineContext) : Closeable, CoroutineScope { override val coroutineContext: CoroutineContext = context override fun close() { coroutineContext.cancel() } } AAC-ViewModel੄ ഛ੢ ೣࣻ۽ viewModelScope੄ ղࠗ ௏٘ੑפ׮. CoroutineScopeਸ ղࠗ੸ਵ۽ ࢎਊೞҊ, cancel दఃӝ ਤೠ Closable ࢚ࣘ ௿ېझо ҳഅغয ੓णפ׮. AAC-ViewModel destroy द ೣԋ ઙܐೞب۾ ٜ݅যઉ੓Ҋ, SupervisorJob()җ Mainਸ ӝ ࠄਵ۽ ࢎਊ೤פ׮.
  10. ੉ ௏٘۽ ঌইࠅ ղਊ • CoroutinesScope(GlobalScope਷ ૑ন) • Coroutines ز੘ೞӝ

    ਤೠ launch • CoroutineContext(SupervisorJob, Dispatchers) • suspend function • Coroutine ઙܐ ୊ܻ
  11. CoroutinesScope public interface CoroutineScope { /** * The context of

    this scope. * Context is encapsulated by the scope and used for implementation of coroutine builders that are extensions on the scope. * Accessing this property in general code is not recommended for any purposes except accessing the [Job] instance for advanced usages. * * By convention, should contain an instance of a [job][Job] to enforce structured concurrency. */ public val coroutineContext: CoroutineContext } CoroutineScope੄ ୭࢚ਤ interface ੿੄ੑפ׮.
  12. CoroutinesScope ৉ೡ • Coroutine ੿੄ܳ ਤೠ Scope ઁҕ • CoroutineContext

    ഋకܳ ૑੿ • Default, IO, Android Main • launch, async ١ਸ ా೧ coroutine प೯ ഋకܳ ੿੄
  13. Coroutines ز੘ೞӝ ਤೠ launch class MainViewModel : ViewModel() { init

    { viewModelScope.launch(Dispatchers.IO) { // 생략 } } }
  14. Coroutines ز੘ೞӝ ਤೠ launch public fun CoroutineScope.launch( context: CoroutineContext =

    EmptyCoroutineContext, start: CoroutineStart = CoroutineStart.DEFAULT, block: suspend CoroutineScope.() -> Unit ): Job { val newContext = newCoroutineContext(context) val coroutine = if (start.isLazy) LazyStandaloneCoroutine(newContext, block) else StandaloneCoroutine(newContext, active = true) coroutine.start(start, coroutine, block) return coroutine } launch੄ start ӝࠄ ز੘਷ CoroutineStart.DEFAULT۽ ૊द प೯ਸ ӝࠄਵ۽ ೠ׮. LAZY۽ ߸҃ द return ೠ Jobਸ ੉ਊ೧ lazy start() ೡ ࣻ ੓׮. contextח ߹ب۽ ૑੿ೞ૑ ঋਵݶ EmptyCoroutineContext੉ݴ, newCoroutineContext۽ parent CoroutineScope੄ context৬ ೤ ࢿೠ׮. newCoroutineContext(context) start: CoroutineStart = CoroutineStart.DEFAULT, context: CoroutineContext = EmptyCoroutineContext, : Job CoroutineScope.launch
  15. Coroutines ز੘ೞӝ ਤೠ launch • CoroutineScopeਸ प೯ೞӝ ਤೠ launch, async/await

    ١੉ ੓׮ • launch ࢎਊद ೦࢚ ࢚ਤ Context + ࢜۽਍ Conextܳ ೤୛ newContext() ࢤࢿ • launch੄ ӝࠄ ز੘਷ ૊द प೯੉׮. • launch੄ return ч਷ Jobਸ ߈ജ, प೯ Ѿҗܳ ঳Ҋ र׮ݶ async/await ഝਊ
  16. CoroutineStart • DEFAULT : ૊द प೯, ݽٚ ௏ܖ౯਷ DEFAULTо ӝࠄ

    • LAZY : וܻӝ प೯, job ё୓ܳ ੉ਊ start()ܳ ഐ୹೧઻ঠ ೠ׮
  17. Coroutines ز੘ೞӝ ਤೠ launch class MainViewModel : ViewModel() { init

    { val job = viewModelScope.launch(start = CoroutineStart.LAZY, context = Dispatchers.IO) { // 생략 } job.start() } } launchо lazy۽ ز੘ೞӝ ਤ೧ࢲח startী ২࣌ਸ ୶оೞҊ, launch ز੘द ߹ب੄ contextо ೙ਃೞ׮ݶ Dispatchers.IOܳ ૑੿೤פ׮. Lazy दীח jobীࢲ start()ܳ ഐ୹೤פ׮.
  18. Dispatchers • Default : JVM झۨ٘ shared pool ӝળਵ۽ ز੘,

    CPU ௏য ࣻ৬ زੌೞ૑݅ ୭ ࣗ 2ѐܳ ࢎਊ ( RxJava : Schedulers.computation() ) • IO : Thread ҕਬ ಽ۽ ز੘ ( RxJava : Schedulers.io() ) • Main : Android UI ୊ܻ ( RxJava : Android.main ) • Uncon fi ned : ౠ੿ झۨ٘ী ઁೠغ૑ ঋח ௏ܖ౯
  19. Job • Job() : ೞա੄ ੘স੉ۄب લਵݶ ੹୓ ઙܐ •

    SupervisorJob() : ೞա੄ ੘স੉ ઙܐغযب ׮ܲ ੘স(child/parent)ী ৔ೱਸ ޷ ஖૑ ঋ਺
  20. Job

  21. Job • ӝࠄ ؀ӝ • join() : scope ز੘੉ ՘զ

    ٸө૑ ؀ӝೞݴ, CoroutinScope উীࢲ ഐ୹ оמ • प೯ • start() : Scope ࢚కܳ ഛੋೞݴ, ই૒ द੘ೞ૑ ঋওਸ ҃਋ start • ஂࣗ • cancelAndJoin() : ઙܐ റ ઙܐ ؀ӝ • cancel() : ੘স ઺ੋ ز੘ਸ ઙܐ ਬب • cancelChildren() : Children ੟ী ؀ೠ ઙܐ ਬب
  22. CoroutineExceptionHandler • CoroutineExceptionHandler • CoroutinesScope੉ о૑ݶ ݽٚ ೞਤ job ٜ੄

    Exceptionਸ ҙܻ • launchо о૑ݶ launch ੘স ߂ ೞਤ job ٜ੄ exceptionਸ ҙܻ • try/catch or kotlin.runCatching ࢎਊ द ૒੽ ҙܻೠ׮ח ੄޷
  23. CoroutineContext @Test fun test() = runBlocking { val coroutineException =

    CoroutineExceptionHandler { coroutineContext, throwable -> val name = coroutineContext[CoroutineName.Key] println("name $name + throwable ${throwable.message}") } val job = CoroutineScope(Dispatchers.IO).launch(coroutineException + CoroutineName("Name")) { kotlin.runCatching { throw Exception("runCatching") }.onFailure { println("throwable runCatching ${it.message}") } throw Exception("Out") } job.join() } coroutineExceptionਸ launchী ನೣೞҊ, CoroutineNameਸ ૑੿ೞ৓णפ׮. coroutineExceptionীࢲח CoroutineNameਵ۽ যځ ೠ ز੘ীࢲ য়ܨо ߊࢤೞ৓ח૑ ҳ࠙ೡ ࣻ ੓ѱ ؾפ׮. runCatchingਸ ࢎਊೞݶ ૒੽ য়ܨܳ ҙܻೣਸ ڷೞҊ, ݅ড ҕా੄ য়ܨܳ ୶о۽ ੟ইঠ ೠ׮ݶ throwܳ ୶о۽ ߊࢤदఃݶ ؾפ׮.
  24. CoroutineContext public interface CoroutineContext { public operator fun plus(context: CoroutineContext):

    CoroutineContext = if (context === EmptyCoroutineContext) this else // fast path -- avoid lambda creation context.fold(this) { acc, element -> val removed = acc.minusKey(element.key) if (removed === EmptyCoroutineContext) element else { // make sure interceptor is always last in the context (and thus is fast to get when present) val interceptor = removed[ContinuationInterceptor] if (interceptor == null) CombinedContext(removed, element) else { val left = removed.minusKey(ContinuationInterceptor) if (left === EmptyCoroutineContext) CombinedContext(element, interceptor) else CombinedContext(CombinedContext(left, element), interceptor) } } } } CoroutineContext੄ ղࠗ ௏٘ ઺ plus ࠗ࠙ੑפ׮.
  25. suspend function ٣ஹ౵ੌ private final Object getMessage(Continuation $completion) { return

    "World!"; } private open class StandaloneCoroutine( parentContext: CoroutineContext, active: Boolean ) : AbstractCoroutine<Unit>(parentContext, initParentJob = true, active = active) public abstract class AbstractCoroutine<in T>( parentContext: CoroutineContext, initParentJob: Boolean, active: Boolean ) : JobSupport(active), Job, Continuation<T>, CoroutineScope suspend function੄ ٣ஹ౵ੌ ௏٘ח getMessage() ࠗ࠙ੑפ׮. suspendܳ ನೣೡ ҃਋ Continuationਸ ౵ۄ޷ఠ۽ ߉חؘ, ੉۽ ੋ೧ CoroutineScope ղীࢲ ௏٘о प೯غযঠ ೣਸ ੄޷೤פ׮. launch੄ ղࠗ ௏٘ܳ ୶੸೧ࠁݶ StandaloneCoroutine ղࠗ੄ AbstractCoroutine੉ ੓Ҋ, ೠ ߣ ؊ ୶੸ೞݶ Continuation<T>ܳ ࢚ࣘ߉Ҋ ੓਺ਸ ഛੋ೧ࠅ ࣻ ੓णפ׮. * ٣ஹ౵ੌ Ѿҗח ׳ۄ૕ ࣻ ੓ ਵפ ױࣽ ଵҊ݅ ೞࣁਃ.
  26. suspend function public interface Continuation<in T> { /** * The

    context of the coroutine that corresponds to this continuation. */ public val context: CoroutineContext /** * Resumes the execution of the corresponding coroutine passing a successful or failed [result] as the * return value of the last suspension point. */ public fun resumeWith(result: Result<T>) } suspend ٣ஹ౵ੌ द ֢୹ػ Continuation<T> interfaceח resumeWith()ਸ ನೣ೤פ׮. Continuationীࢲ ੉੹ਵ۽ ࠂӈೡ ٸח resumeWith()ਸ ഐ୹೧ чਸ ֈѹ઱ݶ ੉੹੄ ࢚క۽ جইцפ׮.
  27. Coroutine ઙܐ ୊ܻ • ઙܐ ୊ܻ ߑߨ • Coroutine ୡӝച

    दী ੸ਊೠ Job ژח CoroutineContext ੉ਊೠ ઙܐ • пп੄ launch੄ return jobਸ ੉ਊೠ ઙܐ • ઙܐೞ૑ ޅೞח ࢚ട • for ܖ೐ীࢲח ௏ܖ౯ cancel()ਸ ೞ؊ۄب ઙܐೞ૑ ޅೠ׮ (׮਺੢ ଵઑ) • ܖ೐ীࢲ ௏ܖ౯ ઙܐܳ ਤೠ ߹ب੄ ୊ܻ ೙ਃ
  28. Coroutine ઙܐ ୊ܻ @Test fun testList() = runBlocking { val

    scope = CoroutineScope(Dispatchers.IO) val job = scope.launch { (0..1_000).forEach { println("data $it") } } scope.launch { delay(5) println("Call cancel”) job.cancel() } job.join() println("run!") } data 0 data 1 … data 33 Call cancel data 34 … data 1000 run! ੉ ௏٘ח forEach {}۽ 0ࠗఠ 1_000ө૑ ܖ೐ܳ ز੘೤פ׮. 5ms റ cancel()ਸ ೮૑݅ Ѿҗח data 1000ө૑ ݽف ୹۱ റ ઙܐؾפ׮. ੉ ௏٘ח cancel()ਸ ೞ؊ۄب ઙܐೡ ߑߨ੉ হणפ׮.
  29. Coroutine ઙܐ ୊ܻ - isActive ࢚క۽ ഛੋ @Test fun testList()

    = runBlocking { val scope = CoroutineScope(Dispatchers.IO) val job = scope.launch { (0..1_000).forEach { if (isActive) { println("data $it") } else { cancel() } } } scope.launch { delay(5) println("Call cancel") job.cancel() } job.join() println("run!") } data 0 data 1 … data 82 Call cancel data 83 … data 104 run! cancel੉ ز੘ೞѱ ٜ݅۰ݶ isActive ࢚కܳ ୓௼ೞҊ, ੉ܳ ੿૑ೡ ࣻ ੓ب۾ ୶о ੘স੉ ೙ਃ೤פ׮. ੉ ࢠ೒ীࢲח isActive ࢚కо ইפۄ ݶ cancel()ਸ ୊ܻ೤פ׮. forEach {} ղী cancel()ਸ ୶оೞ৓ӝী, 0~1_000ө૑о ইצ 5ms റ ઙܐ೤פ׮.
  30. Coroutine ઙܐ ୊ܻ - asFlow, cancellable @Test fun testList() =

    runBlocking { val scope = CoroutineScope(Dispatchers.IO) val job = scope.launch { (0..1_000).asFlow().cancellable().collect { println("data $it") } } scope.launch { delay(5) println("Call cancel") job.cancel() } job.join() println("run!") } data 0 data 1 … data 31 Call cancel data 32 … data 40 run! asFlow()۽ ߸҃ೞҊ, cancellable()ਸ ୊ܻೞח ߑߨب ੓णפ׮. ੉ ࠗ࠙਷ ޙࢲী ੜ ա৬੓ਵפ ޙࢲܳ ଵҊೞࣁਃ.
  31. Flow • Flow : ColdFlow • чਸ ࣽର੸ਵ۽ ൗ۰ࠁմ׮. •

    collect {}ਸ ೧ঠ ز੘ • map, fi lter, take, zip ١җ э਷ ൒ܴ੄ ઺р ো࢑੗ܳ ઁҕ
  32. Flow @Test fun testFlow() = runBlocking { flow { (1..100).forEach

    { emit(it) } } .filter { it < 50 } .flowOn(Dispatchers.IO) .collect { println("data $it") } } fl ow ࢠ೒ ௏٘۽ 1ࠗఠ 100ө૑ ܖ೐ܳ ز੘ೞҊ, ࣽࢲ؀۽ fi lter৬ collect{}ীࢲ ୹۱ೞח ௏٘ੑפ׮.
  33. Flow + combine @Test fun testFlowZip() = runBlocking { val

    flowTest = flow { (1..10).forEach { emit(it) } } flowOf(2).combine(flowTest) { a, b -> a * b } .collect { println("it $it") } } fl owOf۽ ೦࢚ 2৬ combineਵ۽ fl owTest੄ 1ࠗఠ 10ө૑੄ чਸ ൗ۰ղ݀פ׮. ੉ٸ a * bܳ ୊ܻ೤פ׮.
  34. Flow • fl owח fl ow {} উীࢲ emit ೧ঠ

    ೠ׮. (RxJava create) • fl owOf()ח 1ഥ ࢿ ؘ੉ఠী ഝਊೡ ࣻ ੓׮. (RxJava just) • fl owOn੄ ز੘਷ Dispatcher ੸ਊҗ زदী ׮਺ fl owOn੉ য়ӝ ੹ө૑ زੌೠ झ ா઴۞ীࢲ ز੘ೠ׮. (RxJava subscribeOn, observeOn) • Collect ೣࣻח suspend function੉ݴ, CoroutineScope ղীࢲ ز੘ೠ׮. (RxJava subscribe) • Error ୊ܻח Coroutineীࢲ ࢎਊೞ؍ ߑधҗ زੌ(try/catch or CoroutineExceptionHandler)
  35. Callback ؘ੉ఠܳ Flow۽ • ৻ࠗ CallbackEventܳ Flow۽ ੹ജೞח ߑߨ •

    callbackFlowܳ ഝਊ • ଵҊ ੗ܐ • https://thdev.tech/kotlin/2020/12/07/Coroutines-Flow-Callback/ • https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/ kotlinx.coroutines. fl ow/callback- fl ow.html
  36. Callback ؘ੉ఠܳ Flow۽ class FlowMotionEvent { fun createMotionEvent(event: View): Flow<MotionEvent>

    = callbackFlow { val callback = View.OnTouchListener { _, p1 -> trySendBlocking(p1) true } event.setOnTouchListener(callback) awaitClose { event.setOnTouchListener(null) } } } awaitClose ೙ࣻ ௏٘ blocking হח ҃਋ী݅!
  37. Callback ؘ੉ఠܳ Flow۽ public fun <E> SendChannel<E>.trySendBlocking(element: E): ChannelResult<Unit> {

    /* * Sent successfully -- bail out. * But failure may indicate either that the channel it full or that * it is close. Go to slow path on failure to simplify the successful path and * to materialize default exception. */ trySend(element).onSuccess { return ChannelResult.success(Unit) } return runBlocking { val r = runCatching { send(element) } if (r.isSuccess) ChannelResult.success(Unit) else ChannelResult.closed(r.exceptionOrNull()) } } trySendBlocking੄ ղࠗ ௏٘ীࢲ ঌ ࣻ ੓૑݅ runBlockingਸ ഝਊೞҊ ੓णפ׮. runBlocking਷ UIী ؀ೠ lock੉ ߊࢤೡ ࣻ ੓ӝ ٸޙ ী trySendBlocking ௏٘੄ ࢎਊ द UI৬ ޖҙೠ Ҕীࢲ ࢎਊ੉ ೙ਃೞפ ઱੄೧ࢲ ࢎਊ೧ঠ ೤פ׮.
  38. SharedFlow • SharedFlow • HotFlow • Broadcast ߑधਵ۽ ؘ੉ఠܳ ҕਬ

    • ҕਬ ൒ܴ਷ ഝࢿ ੋझఢझо collect৬ ة݀੸ਵ۽ ઓ੤
  39. MutableSharedFlow • ৈ۞ Ҕীࢲ ਽׹ਸ ߉ইঠ ೡ ҃਋ ਬਊ •

    replay(0), extraBu ff erCapacity(0), Bu ff erOverFlow(Suspend) ࢚కܳ Ѿ੿ оמ • launchInਸ ݃૑݄ী ੸য઱য collect{} হ੉ ز੘ оמ
  40. MutableSharedFlow - ClickEvent private val mutableSharedFlow = MutableSharedFlow<Int>( extraBufferCapacity =

    1, onBufferOverflow = BufferOverflow.DROP_OLDEST ) init { mutableSharedFlow .onEach { Log.e("TEMP", "clickCount $it") } .flowOn(Dispatchers.Main) .launchIn(viewModelScope) } private var count = 0 fun clickEvent() { mutableSharedFlow.tryEmit(count++) } MutableSharedFlowܳ ੉ਊೠ clickEvent ୊ܻ ࠗ࠙ੑפ׮. ௿ܼ ੉߮౟ח extraBufferܳ 1ѐܳ ୶оೞҊ, Over fl owܳ Drop oldest۽ ୊ܻ೧ સפ׮. tryEmit()ਵ۽ countܳ োࣘ੸ਵ۽ ֈӝחؘ, 0, 1, 2, …ਸ ୊ܻ೤פ׮.
  41. MutableSharedFlow - ClickEvent public fun <T> Flow<T>.launchIn(scope: CoroutineScope): Job =

    scope.launch { collect() // tail-call } ଵҊ۽ launchIn੄ ղࠗ ௏٘ੑפ׮. ֈѹ߉਷ scopeਸ ੉ਊ೧ launchܳ ୊ܻೞҊ, collect()ਸ ഐ୹೤פ׮.
  42. StateFlow • ݃૑݄ ࢚క чਸ ӝর೧ঠ ೡ ҃਋ ਬਊ •

    ୡӝച чਸ ೣԋ ֈѹঠ ೠ׮ • زੌೠ ч਷ ޖदೠ׮ • ੑ۱ೠ ч਷ Read-only۽ ز੘ೠ׮
  43. StateFlow private val stateFlow = MutableStateFlow(true) init { stateFlow .onEach

    { Log.e("TEMP", "value change $it") } .flowOn(Dispatchers.IO) .launchIn(viewModelScope) } fun clickEvent() { stateFlow.value = stateFlow.value.not() } MutableStateFlow۽ ୡӝച чਸ ೣԋ ֈѹસפ׮. StateFlowח زੌೠ ч੉ 1ഥ ੉࢚ ٜযয়ݶ ղࠗ੸ਵ۽ ޖदೞѱ ؾפ׮. ੉ ௏٘ীࢲ trueܳ 1ߣ ੉࢚ ֈӝݶ ୐ ߣ૩ value݅ streamਵ۽ ղ۰оҊ, ف ߣ૩ trueח ޖद೤פ׮.
  44. Coroutines Flow test @OptIn(ExperimentalTime::class) @Test fun test() = runBlocking {

    flowOf("one", "two").test { Assert.assertEquals("one", expectItem()) Assert.assertEquals("two", expectItem()) expectComplete() } } test{}ח runBlocking {} উীࢲ ഐ୹೧ঠ ೞݴ, fl ow੄ ҃਋ ೦࢚ expectComplete()ܳ ഐ୹೧ ઱যঠ ೤פ׮.
  45. Coroutines SharedFlow test @ExperimentalTime @Test fun testSharedFlow() = runBlocking {

    val mutableSharedFlow = MutableSharedFlow<Int>(replay = 0) mutableSharedFlow.emit(1) mutableSharedFlow.test { Assert.assertEquals(expectItem(), 1) cancelAndConsumeRemainingEvents() } } MutableSharedFlowب turbinਸ ഝਊೡ ࣻ ੓णפ׮. SharedFlow੄ ҃਋ ݃૑݄ী cancelAndConsumeRemainingEvents()ܳ ഐ୹ ೧ঠ ઙܐо ؾפ׮.
  46. RxJava vs Flow RxJava Flow ੿੄ Flowable, Observable, Single ١

    fl ow, SharedFlow, StateFlow ੹୓ झாે۞ ૑੿ subscribeOn(schedulers.io()) fl owOnী ٮۄ ز੘ झாે۞ ߸҃ observeOn(schedulers.io()) fl owOn(CoroutineContext) झாે۞ ߧਤ observeOnীࢲ ੿੄ೠ ׮਺ࠗఠ ݽف ੸ਊ ׮਺ fl owOn੄ ੿੄о য়ӝ ੹ө૑ زੌೞѱ ୊ܻ द੘ subscribe ੿੄о ੓যঠ ز੘ collectী ٮۄ ز੘ CoroutineScope ղীࢲ ز੘
  47. RxJava > Flow or Coroutines • RxJava੄ ௏٘ܳ ׼੢ ѥযղӝ

    য۵׮ݶ Coroutines rx2 • https://github.com/Kotlin/kotlinx.coroutines/tree/master/reactive/ kotlinx-coroutines-rx2 • ӝઓ Repository੄ RxJavaܳ ߸҃ೠ׮ݶ Flowܳ ࢎਊ೧ ߸҃ оמ