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

Kotlin Coroutines and Flow.

Kotlin Coroutines and Flow.

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

TaeHwan

July 26, 2021
Tweet

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ܳ ࢎਊ೧ ߸҃ оמ