Slide 1

Slide 1 text

Introduction to Kotlin Flows Armando Picón Senior Android Developer at Cornershop Inc. @devpicon https://linktr.ee/devpicon

Slide 2

Slide 2 text

Flows? • Kotlin Flows should be used when you need to return multiple asynchronously computed values • Flows are cold streams • Flow is inspired by reactive streams or reactive frameworks like RxJava

Slide 3

Slide 3 text

Emitter Collector

Slide 4

Slide 4 text

Emitter Collector flow{ emit() } collect()

Slide 5

Slide 5 text

Emitter Collector flow{ emit() } collect() Flow builder

Slide 6

Slide 6 text

Flow builders • flow{} -> most basic one, create a flow from the given suspendable block • flowOf() -> defines a flow emitting a fixed set of values • .asFlow() -> extension function for collections and sequences

Slide 7

Slide 7 text

flow{ emit() } collect() Flow builder Emitter Collector

Slide 8

Slide 8 text

flow{ emit() } collect() map{} filter{} transform{} take() Flow builder Emitter Collector

Slide 9

Slide 9 text

flow{ emit() } collect() intermediate operators map{} filter{} transform{} take() Flow builder Emitter Collector

Slide 10

Slide 10 text

Intermediate flow operators • map{} -> returns a flow containing the results of applying the given transform function to each value of the original flow • filter{} -> returns a flow containing only values of the original flow that matches the given predicate • transform{} -> it can be used to imitate simple transformations as well more complex transformations. We can emit arbitrary values an arbitrary number of times • take() -> cancel the execution of the flow when the corresponding limit is reached

Slide 11

Slide 11 text

flow{ emit() } collect() map{} filter{} transform{} take() Flow builder intermediate operators Emitter Collector

Slide 12

Slide 12 text

flow{ emit() } collect() Terminal flow operator map{} filter{} transform{} take() Flow builder intermediate operators Emitter Collector

Slide 13

Slide 13 text

Terminal flow operators • collect{} -> collects the given flow with a provided action. If any exception occurs during collect or in the provided flow, this exception is rethrown from this method • reduce{} -> accumulates value starting with the first element and applying operation to current accumulator value and each element. Throws NoSuchElementException if flow was empty • fold{} -> accumulates value starting with initial value and applying operation current accumulator value and each element They are suspending functions that start a collection of the flow

Slide 14

Slide 14 text

Terminal flow operators • first{} -> returns the first element emitted by the flow and then cancels flow's collection. Throws NoSuchElementException if the flow was empty • single{} -> awaits for one and only one value to be published. Throws NoSuchElementException for empty flow and IllegalStateException for flow that contains more than one element They are suspending functions that start a collection of the flow

Slide 15

Slide 15 text

Terminal flow operators • toList(), toSet() -> Collects given flow into a destination and convert to collection They are suspending functions that start a collection of the flow

Slide 16

Slide 16 text

Context preservation • Collections always happens in the context of the calling coroutine • You can’t change manually the context under a collection is being executed • Using of flowOn function is the only to change the context of the flow emission

Slide 17

Slide 17 text

Flows are sequential • Each individual collection of a flow is performed sequentially unless special operators that operate on multiple flows are used. • What happens if the collector and emitter are slow?

Slide 18

Slide 18 text

Emitter Collector delay(100) emit delay(100) println(it) delay(100) emit delay(100)

Slide 19

Slide 19 text

Could be the sequential execution an issue? • Sequential execution could be an issue when both the emitter and the collector take too long to processing each element • Remember that usually the flows run under the same context into the same coroutine • Can we decouple the emitter and the collector without changing the code?

Slide 20

Slide 20 text

Challenges to decouple the emitter and the collector • Run the emitter in a separate coroutine from the collector would do both concurrent • With two separate coroutines we need to establish some communication between both of them • Here is where Channels enter to scene providing a mechanism where we can send the elements from the emitter and receive them in another one, through a channel.

Slide 21

Slide 21 text

Buffer operator • Buffers flow emissions via channel of a specified capacity and runs collector in a separate coroutine. Normally, flows are sequential. It means that the code of all operators is executed in the same coroutine. • The buffer operator creates a separate coroutine during execution for the flow it applies to.

Slide 22

Slide 22 text

Emitter Collector delay(100) emit delay(100) println(it) delay(100) emit delay(100) println(it) delay(100) emit

Slide 23

Slide 23 text

Composing multiple flows • zip() • combine()

Slide 24

Slide 24 text

Flattening flows • flatMapConcat {} - transforms elements emitted by the original flow by applying transform, that returns another flow, and then concatenating and flattening these flows • flatMapMerge { } - transforms elements emitted by the original flow by applying transform, that returns another flow, and then merging and flattening these flows. • flatMapLatest {} - returns a flow that switches to a new flow produced by transform function every time the original flow emits a value. When the original flow emits a new value, the previous flow produced by transform block is cancelled.

Slide 25

Slide 25 text

Composing multiple flows • zip() - combines the corresponding values of two flows • combine() - when flow represents the most recent value of a variable or operation, it might be needed to perform a computation that depends on the most recent values of the corresponding flows and to recompute it whenever any of the upstream flows emit a value

Slide 26

Slide 26 text

Exception transparency • Exceptions can be rethrown using throw. • Exceptions can be turned into emission of values using emit from the body of catch. • Exceptions can be ignored, logged, or processed by some other code.

Slide 27

Slide 27 text

References • Asynchronous Flow https://kotlinlang.org/docs/reference/coroutines/flow.html • Cold flows, hot channels https://medium.com/@elizarov/cold-flows-hot-channels-d74769805f9 • Simple design of Kotlin Flow https://medium.com/@elizarov/simple-design-of-kotlin-flow-4725e7398c4c • Kotlin Flows and Coroutines https://medium.com/@elizarov/kotlin-flows-and-coroutines-256260fb3bdb

Slide 28

Slide 28 text

Recommended lectures • Asynchronous development in Android: RxJava vs Kotlin Flow https://medium.com/makingtuenti/asynchronous-development-in-android-rxja va-vs-kotlin-flow-f7fdf2e2f81b • From RxJava 2 to Kotlin Flow: Threading https://proandroiddev.com/from-rxjava-2-to-kotlin-flow-threading-8618867e1 955 • The Real Kotlin Flow benefits over RxJava https://proandroiddev.com/the-real-kotlin-flow-benefits-over-rxjava-c19b99ba 6eb9

Slide 29

Slide 29 text

Codalot Podcast anchor.fm/codalot yt.vu/+devpicon ¡Gracias!