Slide 1

Slide 1 text

Coroutines Taehwan

Slide 2

Slide 2 text

য়ט ঌইࠅ ղਊ • ࢎਊߨ਷ ݒ਋ рױ೤פ׮. • ࢎਊߨࠁױ ղࠗ ௏٘ܳ ా೧ ௏ܖ౯ਸ ઑӘ ؊ ࢓ಝࠇפ׮. • ҃೷࢚ ԙ ঌইفݶ જਸ ղਊਸ ୶о೤פ׮.

Slide 3

Slide 3 text

Subroutine

Slide 4

Slide 4 text

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.

Slide 5

Slide 5 text

Subroutine fun runTest() fun MutableList.sum() mutableList().sum() return sumValue +1 +2 . . .

Slide 6

Slide 6 text

Coroutines

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

Coroutines Run routine fun Int.sum() Loop fun Int.sum() Loop fun Int.sum() Loop fun Int.sum() Loop 10.sum() . . . Entry point ৈ۞ ѐ ೲਊ

Slide 10

Slide 10 text

Kotlin Coroutines

Slide 11

Slide 11 text

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.

Slide 12

Slide 12 text

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ܳ ഝਊೞݶ ؾפ׮.

Slide 13

Slide 13 text

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۽ ߸҃೤פ׮.

Slide 14

Slide 14 text

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ਸ ӝ ࠄਵ۽ ࢎਊ೤פ׮.

Slide 15

Slide 15 text

੉ ௏٘۽ ঌইࠅ ղਊ • CoroutinesScope(GlobalScope਷ ૑ন) • Coroutines ز੘ೞӝ ਤೠ launch • CoroutineContext(SupervisorJob, Dispatchers) • suspend function • Coroutine ઙܐ ୊ܻ

Slide 16

Slide 16 text

CoroutinesScope

Slide 17

Slide 17 text

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 ੿੄ੑפ׮.

Slide 18

Slide 18 text

CoroutinesScope ৉ೡ • Coroutine ੿੄ܳ ਤೠ Scope ઁҕ • CoroutineContext ഋకܳ ૑੿ • Default, IO, Android Main • launch, async ١ਸ ా೧ coroutine प೯ ഋకܳ ੿੄

Slide 19

Slide 19 text

Coroutines ز੘ೞӝ ਤೠ launch

Slide 20

Slide 20 text

Coroutines ز੘ೞӝ ਤೠ launch class MainViewModel : ViewModel() { init { viewModelScope.launch(Dispatchers.IO) { // 생략 } } }

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

Coroutines ز੘ೞӝ ਤೠ launch • CoroutineScopeਸ प೯ೞӝ ਤೠ launch, async/await ١੉ ੓׮ • launch ࢎਊद ೦࢚ ࢚ਤ Context + ࢜۽਍ Conextܳ ೤୛ newContext() ࢤࢿ • launch੄ ӝࠄ ز੘਷ ૊द प೯੉׮. • launch੄ return ч਷ Jobਸ ߈ജ, प೯ Ѿҗܳ ঳Ҋ र׮ݶ async/await ഝਊ

Slide 23

Slide 23 text

CoroutineStart • DEFAULT : ૊द प೯, ݽٚ ௏ܖ౯਷ DEFAULTо ӝࠄ • LAZY : וܻӝ प೯, job ё୓ܳ ੉ਊ start()ܳ ഐ୹೧઻ঠ ೠ׮

Slide 24

Slide 24 text

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()ܳ ഐ୹೤פ׮.

Slide 25

Slide 25 text

CoroutineContext 
 SupervisorJob, Dispatchers, Etc

Slide 26

Slide 26 text

CoroutineContext • CoroutineContextח ௏ܖ౯੄ ز੘, ҙܻܳ ୊ܻೞӝ ਤೠ Contextܳ ઁҕ

Slide 27

Slide 27 text

CoroutineContext CloseableCoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) Job Dispatchers CoroutinesContextח + ো࢑ਵ۽ ੉যࠢ੉ӝ оמ

Slide 28

Slide 28 text

Dispatchers • Default : JVM झۨ٘ shared pool ӝળਵ۽ ز੘, CPU ௏য ࣻ৬ زੌೞ૑݅ ୭ ࣗ 2ѐܳ ࢎਊ ( RxJava : Schedulers.computation() ) • IO : Thread ҕਬ ಽ۽ ز੘ ( RxJava : Schedulers.io() ) • Main : Android UI ୊ܻ ( RxJava : Android.main ) • Uncon fi ned : ౠ੿ झۨ٘ী ઁೠغ૑ ঋח ௏ܖ౯

Slide 29

Slide 29 text

Job • Job() : ೞա੄ ੘স੉ۄب લਵݶ ੹୓ ઙܐ • SupervisorJob() : ೞա੄ ੘স੉ ઙܐغযب ׮ܲ ੘স(child/parent)ী ৔ೱਸ ޷ ஖૑ ঋ਺

Slide 30

Slide 30 text

Job

Slide 31

Slide 31 text

Job • ӝࠄ ؀ӝ • join() : scope ز੘੉ ՘զ ٸө૑ ؀ӝೞݴ, CoroutinScope উীࢲ ഐ୹ оמ • प೯ • start() : Scope ࢚కܳ ഛੋೞݴ, ই૒ द੘ೞ૑ ঋওਸ ҃਋ start • ஂࣗ • cancelAndJoin() : ઙܐ റ ઙܐ ؀ӝ • cancel() : ੘স ઺ੋ ز੘ਸ ઙܐ ਬب • cancelChildren() : Children ੟ী ؀ೠ ઙܐ ਬب

Slide 32

Slide 32 text

CoroutineName • ز੘ ઺ੋ Coroutine ੉ܴਸ ૑੿ೡ ࣻ ੓׮ .launch(CoroutineName("Name"))

Slide 33

Slide 33 text

CoroutineExceptionHandler • CoroutineExceptionHandler • CoroutinesScope੉ о૑ݶ ݽٚ ೞਤ job ٜ੄ Exceptionਸ ҙܻ • launchо о૑ݶ launch ੘স ߂ ೞਤ job ٜ੄ exceptionਸ ҙܻ • try/catch or kotlin.runCatching ࢎਊ द ૒੽ ҙܻೠ׮ח ੄޷

Slide 34

Slide 34 text

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ܳ ୶о۽ ߊࢤदఃݶ ؾפ׮.

Slide 35

Slide 35 text

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 ࠗ࠙ੑפ׮.

Slide 36

Slide 36 text

suspend function

Slide 37

Slide 37 text

suspend function • suspend ఃਕ٘ܳ ୶оೞৈ ೣࣻ ࠙ೡ • suspend ೣࣻח CoroutineScope ղীࢲ ࢎਊ оמ

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

suspend function public interface Continuation { /** * 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) } suspend ٣ஹ౵ੌ द ֢୹ػ Continuation interfaceח resumeWith()ਸ ನೣ೤פ׮. Continuationীࢲ ੉੹ਵ۽ ࠂӈೡ ٸח resumeWith()ਸ ഐ୹೧ чਸ ֈѹ઱ݶ ੉੹੄ ࢚క۽ جইцפ׮.

Slide 40

Slide 40 text

Coroutine ઙܐ ୊ܻ

Slide 41

Slide 41 text

Coroutine ઙܐ ୊ܻ • ઙܐ ୊ܻ ߑߨ • Coroutine ୡӝച दী ੸ਊೠ Job ژח CoroutineContext ੉ਊೠ ઙܐ • пп੄ launch੄ return jobਸ ੉ਊೠ ઙܐ • ઙܐೞ૑ ޅೞח ࢚ട • for ܖ೐ীࢲח ௏ܖ౯ cancel()ਸ ೞ؊ۄب ઙܐೞ૑ ޅೠ׮ (׮਺੢ ଵઑ) • ܖ೐ীࢲ ௏ܖ౯ ઙܐܳ ਤೠ ߹ب੄ ୊ܻ ೙ਃ

Slide 42

Slide 42 text

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()ਸ ೞ؊ۄب ઙܐೡ ߑߨ੉ হणפ׮.

Slide 43

Slide 43 text

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 റ ઙܐ೤פ׮.

Slide 44

Slide 44 text

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()ਸ ୊ܻೞח ߑߨب ੓णפ׮. ੉ ࠗ࠙਷ ޙࢲী ੜ ա৬੓ਵפ ޙࢲܳ ଵҊೞࣁਃ.

Slide 45

Slide 45 text

Flow

Slide 46

Slide 46 text

Flow • Flow : ColdFlow • чਸ ࣽର੸ਵ۽ ൗ۰ࠁմ׮. • collect {}ਸ ೧ঠ ز੘ • map, fi lter, take, zip ١җ э਷ ൒ܴ੄ ઺р ো࢑੗ܳ ઁҕ

Slide 47

Slide 47 text

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{}ীࢲ ୹۱ೞח ௏٘ੑפ׮.

Slide 48

Slide 48 text

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ܳ ୊ܻ೤פ׮.

Slide 49

Slide 49 text

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)

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

Callback ؘ੉ఠܳ Flow۽ class FlowMotionEvent { fun createMotionEvent(event: View): Flow = callbackFlow { val callback = View.OnTouchListener { _, p1 -> trySendBlocking(p1) true } event.setOnTouchListener(callback) awaitClose { event.setOnTouchListener(null) } } } awaitClose ೙ࣻ ௏٘ blocking হח ҃਋ী݅!

Slide 52

Slide 52 text

Callback ؘ੉ఠܳ Flow۽ public fun SendChannel.trySendBlocking(element: E): ChannelResult { /* * 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৬ ޖҙೠ Ҕীࢲ ࢎਊ੉ ೙ਃೞפ ઱੄೧ࢲ ࢎਊ೧ঠ ೤פ׮.

Slide 53

Slide 53 text

SharedFlow

Slide 54

Slide 54 text

SharedFlow • SharedFlow • HotFlow • Broadcast ߑधਵ۽ ؘ੉ఠܳ ҕਬ • ҕਬ ൒ܴ਷ ഝࢿ ੋझఢझо collect৬ ة݀੸ਵ۽ ઓ੤

Slide 55

Slide 55 text

MutableSharedFlow • ৈ۞ Ҕীࢲ ਽׹ਸ ߉ইঠ ೡ ҃਋ ਬਊ • replay(0), extraBu ff erCapacity(0), Bu ff erOverFlow(Suspend) ࢚కܳ Ѿ੿ оמ • launchInਸ ݃૑݄ী ੸য઱য collect{} হ੉ ز੘ оמ

Slide 56

Slide 56 text

MutableSharedFlow - ClickEvent private val mutableSharedFlow = MutableSharedFlow( 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, …ਸ ୊ܻ೤פ׮.

Slide 57

Slide 57 text

MutableSharedFlow - ClickEvent public fun Flow.launchIn(scope: CoroutineScope): Job = scope.launch { collect() // tail-call } ଵҊ۽ launchIn੄ ղࠗ ௏٘ੑפ׮. ֈѹ߉਷ scopeਸ ੉ਊ೧ launchܳ ୊ܻೞҊ, collect()ਸ ഐ୹೤פ׮.

Slide 58

Slide 58 text

StateFlow

Slide 59

Slide 59 text

StateFlow • ݃૑݄ ࢚క чਸ ӝর೧ঠ ೡ ҃਋ ਬਊ • ୡӝച чਸ ೣԋ ֈѹঠ ೠ׮ • زੌೠ ч਷ ޖदೠ׮ • ੑ۱ೠ ч਷ Read-only۽ ز੘ೠ׮

Slide 60

Slide 60 text

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ח ޖद೤פ׮.

Slide 61

Slide 61 text

Coroutines Flow test Turbin

Slide 62

Slide 62 text

Coroutines Flow test https://github.com/cashapp/turbine testImplementation("app.cash.turbine:turbine:0.5.2") Flow పझ౟ܳ ਤೠ turbineਸ ഝਊೡ ࣻ ੓णפ׮.

Slide 63

Slide 63 text

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()ܳ ഐ୹೧ ઱যঠ ೤פ׮.

Slide 64

Slide 64 text

Coroutines SharedFlow test @ExperimentalTime @Test fun testSharedFlow() = runBlocking { val mutableSharedFlow = MutableSharedFlow(replay = 0) mutableSharedFlow.emit(1) mutableSharedFlow.test { Assert.assertEquals(expectItem(), 1) cancelAndConsumeRemainingEvents() } } MutableSharedFlowب turbinਸ ഝਊೡ ࣻ ੓णפ׮. SharedFlow੄ ҃਋ ݃૑݄ী cancelAndConsumeRemainingEvents()ܳ ഐ୹ ೧ঠ ઙܐо ؾפ׮.

Slide 65

Slide 65 text

RxJava > Flow or Coroutines

Slide 66

Slide 66 text

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 ղীࢲ ز੘

Slide 67

Slide 67 text

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