Global CSS droidcon News droidcon Berlin 2019 Share Tweet Flowing in the Deep By Hannes Dorfmann & Gabriel Ittner, Freeletics droidcon Berlin 2019 The Kotlin team introduced a new type called Flow which looks similar to RxJava’s Observable or Flowable. Have you ever wondered what’s the difference between Flow and RxJava? How does Flow work under the hood? How is it connected to Coroutines? How do you write your own operator? What about Kotlin Coroutine Channels? Backpressure? Coroutine Scopes? Join this session to get an introduction into Flow followed by a deep dive into some core aspects of Flow to ultimately feel confident using Flow inside your android app. Transcript English 00:10 good afternoon everyone please take a 00:14 seat 00:16 so my name is Hannes I'm Gabriel and we 00:25 both work for full ethics and since 00:28 you're here today you totally got the 00:31 reference from the stock title to this 00:34 beautiful song right moreover I think 00:39 you are here to help us sing don't you 00:44 so God where do you want to sing no so 00:51 yeah we are actually here to talk about 00:53 flow and to give you an introduction to 00:58 it what it is why you should use it or 01:01 want to use it we will talk about 01:03 operators on flow how they look like how 01:07 they work 01:09 threading which is always an important 01:12 topic for in streams and we will finish 01:16 it off with some useful API so that you 01:18 will want to know about if you want to 01:20 use cut flow right so a little 01:24 disclaimer this talk is a little bit 01:26 more of an advanced talk and you will 01:27 see a lot of code on purpose because we 01:31 really want you to understand what's 01:32 going on under the hood to ultimately 01:34 feel comfortable using it you will get 01:37 also the slats in the online to 01:39 somewhere online will be posted on 01:40 Twitter to go through the code one by 01:43 one in case you would look up would like 01:45 to look up some things afterwards but to 01:48 get started let's take one step back and 01:51 say we have something very simple like 01:53 download something from a web server so 01:56 we have this function like do an HTTP 01:58 request that returns an X whatever 02:00 access could be a list of something 02:02 could be a book could be anything that 02:04 you would grab from HTTP server like I 02:07 think pretty common use case right what 02:10 is the problem of that so if you are 02:12 going to execute this what would happen 02:16 if you run that directly from let's say 02:19 the activities on create method what 02:21 would happen is something like that 02:22 right so AB is not 02:23 responding or it crashes because the 02:25 execute Network because it we network 02:29 your main threat how could we fix that 02:31 so we could fix that by surrounding this 02:34 in a new threat and make it run a 02:36 synchronously right but the next 02:38 question is like what do we do once we 02:43 get the result back so now we have this 02:45 X how do we proceed from there okay on 02:49 Android we could wrap it into a runnable 02:52 and put it on the main thread that on 02:54 the on the main looper to get it back to 02:56 the main thread and execute it and move 02:58 the result where we manipulate the UI 02:60 somehow with the result that we got from 03:02 the back end right another approach 03:05 would be taking one step back and 03:07 looking at the network itself so the 03:10 method itself is returning an X and 03:13 asynchronously what if you what would it 03:15 take to make this method asynchronously 03:17 so we would need something like a 03:20 callback right so we would pass as a 03:22 parameter to this method or to this 03:24 function call back in this case a simple 03:27 callback that gets X which is the result 03:29 that we load from the from the back end 03:31 and returns unit in other words nothing 03:34 and once we have it we would once we got 03:40 there run to retrieve the X we would 03:42 call the callback and make that run in 03:44 the background set over here 03:45 and then we would call it like that from 03:48 the from the main activity or from the 03:50 activity on create the problem with that 03:54 though is composition so what if we have 03:58 to call a callback what would you have 04:00 to do an HTTP request in southern HTTP 04:03 request and southern HTTP request inside 04:05 an HTTP request you see where we're 04:07 going right 04:13 this is also called the callback hell 04:15 and JavaScript developers I'll 04:18 definitely definitely know what we're 04:20 talking about here so let's take one 04:24 step back again so we have this callback 04:26 based API now but there is something 04:30 really neat in Catalan right disco teens 04:33 this suspend keyword by applying that 04:37 one we can do something like that and 04:39 magically things work without having 04:41 this callback hell right but have you 04:43 ever wondered how it works under the 04:45 hood so what is the compiler actually 04:47 doing if we have to suspend a function 04:49 what a compiler is doing is actually 04:53 removing the suspending function 04:55 modifier or like taking the suspending 04:57 function modifier and add a parameter 04:60 for you to this function so you don't 05:04 notice it because the compiler is doing 05:06 it at compile time but there is 05:08 something interesting in that in that 05:10 idea so now we have like this 05:11 continuation object passed in as a 05:13 parameter to this function that used to 05:15 be a suspending function and once we 05:18 have the result of X what the compiler 05:20 does is it adds that line of code that 05:22 says like continuation dot resume and 05:25 this is actually the same idea as having 05:29 a callback before and Phillip Babbage 05:34 I'm not sure if he attended his talk but 05:36 he was also going a little bit more into 05:37 the details so in case you haven't you 05:39 should check out his talk which was 05:40 recorded like any other talk here at 05:43 droidcon balloon but yeah the idea is 05:46 the same right so we have this callback 05:47 to somehow tell someone that we have the 05:50 result now and to make this 05:52 asynchronously working or getting even 05:55 more generalizing this idea we could say 05:58 instead of callback we could call it 05:60 observer and what we end up with is 06:02 actually the observer pattern so let's 06:07 take this one step further so we have 06:10 like this HTTP request but instead of 06:13 that let's move to another example now 06:15 we want to download the video and not 06:19 only do we want to download the video 06:20 but we would also propagate the program 06:23 of how many percent of the video has 06:25 been downloaded yet right so we would 06:27 like to have something like we download 06:30 10% 20% 100% okay how would we do that 06:36 actually with a suspending function 06:39 Gabriel 06:40 so suspending thanks to themselves don't 06:44 only return a single value so we can't 06:47 just do what we did on the slide and add 06:49 a suspend and it will magically work 06:52 like before so the answer to that is 06:56 flow but instead of just putting it 06:59 there instead of the question marks we 07:01 will take a step back and go there 07:04 step-by-step so this is what we had 07:08 before we had the donut video function 07:10 it takes a callback that has progress 07:14 and we're going to try to make it a bit 07:16 more general so first of all we have 07:19 added don't order in TEDA to an 07:21 interface so we can have reusable 07:24 implementations of downloaders second of 07:28 all we are going to make we cannot just 07:35 use it for videos we can do it for other 07:37 things as well so we just call it 07:39 download we might not just want to omit 07:44 the progress so we make it generic and 07:47 then we can emit an object that contains 07:50 other information like download speed or 07:53 the rights we received so far so the 07:58 downloader itself is very generic now 08:01 and but we still have the call back so 08:06 let's create an interface for that as 08:08 well so it's download observer and it 08:11 needs function which we can send the 08:13 data to which we call image and this 08:19 donut observers then use on top so for 08:23 download this is a super nice generic 08:27 abstraction and we're really happy with 08:30 that but this isn't actually limit down 08:34 orders so we could use that for 08:37 anything that uses the observer pattern 08:39 so let's make it this way so on the Left 08:43 we will keep the downloader and on the 08:46 right we will transform this to 08:47 something very generic so the first step 08:52 for that is to rename the download 08:56 function we will call collect because it 08:58 collects values that we want to observe 09:03 the next step and is to rename the 09:07 observer to a collector because it 09:09 receives it receives those values from 09:11 collect and now we still have that 09:16 downloader name and the interface so we 09:18 will rename it to flow which is our 09:23 topic and now the collector will be a 09:28 flow collector because it collects from 09:30 the flow and that's basically flow from 09:36 the cortines library all well almost so 09:40 there's actually a suspending function 09:43 both of them so we will see later on why 09:47 this is useful but this really is flow 09:50 and flow collector like it is in the 09:52 koreans library we didn't remove any 09:55 code there and it's really just that 09:58 generic observer pattern that we showed 10:01 in the beginning so we have the this 10:04 slide earlier the dona video we didn't 10:07 know what to return yet so we will turn 10:10 the flow now and how do we actually 10:14 implement that methods so in the flow 10:17 library there is a builder function it's 10:20 also called flow but it's not with a 10:23 capital letter 10:23 and it takes a lambda that is operates 10:28 on a flow collector so if we want to use 10:31 that we at equals flow and then in the 10:36 lambda that this is a flow collector so 10:39 we can't call the image function on the 10:42 flow collector to actually emit values 10:44 into the flow so we admit the first 10:47 progress and then the other steps 10:51 right so now we know how we can 10:55 construct a flow now let's let it flow 10:58 right let's see how we can actually use 10:60 that switching to get another example 11:02 let's say we want to emit five values 11:04 and we have like a delay from 100 11:06 milliseconds between all of them so this 11:09 simple for loop should be really 11:11 self-explaining right what we need 11:15 actually to make things run is a scope a 11:19 coding scope so we put this flow put it 11:22 into a current in scope and call launch 11:25 which actually then launch a security in 11:28 the view model there is like this handy 11:30 new scope built in with the with the new 11:34 with the new beta that is scoping 11:39 automatically the the the view models 11:42 coding scope to view model dot unclear 11:46 which means once the view model gets 11:47 destroyed it automatically clears the 11:49 whole scope and cancels all the jobs 11:51 which means cancels all the code teens 11:53 at the end and all the flows in case you 11:55 have flows inside your new model or 11:57 inside the scope of the view model next 12:04 this suspending block here or the next 12:06 thing to notice is that this suspending 12:07 block here is actually then running on a 12:09 coyote which means like now we are in 12:10 the async world so to speak and within 12:13 it we make sure that we are kind of 12:15 propagating something to the to the 12:18 collector right so let's remove a little 12:21 bit now the code of the view model just 12:23 for the sake of better readability let's 12:25 say we have this we run this what what 12:28 do we expect is the outcome of this what 12:31 would you expect to happen well nothing 12:35 happens yet because there's one 12:36 important thing missing like they 12:38 collect and now we kind of get the 12:41 values that are emitted above so let's 12:44 go one one one small step a step so we 12:47 call collect on it and this means now we 12:50 observing the flow 12:52 this means emit notify the observer and 12:56 the observer is the collector right so 12:60 actually this is how we get one value 13:02 from above to 13:04 the collector below alright so as we saw 13:11 the flow collector only half that has 13:13 that single emit method and from other 13:16 reactive libraries we are used to having 13:18 an observer which has an error for 13:20 example so how do we handle the errors 13:23 in flow as an example we have this flow 13:27 builder which just we just post an 13:30 exception and what will happen the 13:35 collect will actually reflow that 13:37 exception and then you can handle the 13:41 error like you would handle any other 13:43 exception you usually handle with a 13:46 try-catch around it and then in the 13:48 catch block you can just write your 13:51 error handling in general though we 13:54 would recommend to not do this and just 13:58 make errors part of your stream so if we 14:02 have like this example which is similar 14:04 to the donor example it makes image some 14:07 progress and then just was in error for 14:10 some reason so we would model it 14:14 something like this you would create a 14:16 seal class which is Donuts letters then 14:19 would have subclasses for progress 14:21 success error and then inside your flow 14:25 you would first omit the progress and 14:28 then when the exception happens you 14:30 would catch it inside and then just omit 14:34 the error and then in the end and 14:36 collect you handle errors like you would 14:38 handle regular progress or success 14:41 updates the other thing that usually in 14:46 observers in the rx vote is uncomplete 14:49 which also is not here so how do we 14:51 handle completion when we have some flow 14:56 that's launched it starts a core routine 14:59 which then will execute the flow method 15:02 which creates the flow then it goes to 15:05 the next one it will call collect and 15:08 then at the end here it will suspend and 15:11 wait in the meantime a second coroutine 15:15 will run 15:16 and will actually execute the inner 15:19 parts of the flow so the do stuff 15:22 whatever it does will get executed and 15:25 then when it emits something collect 15:30 will be the lambda from the collect will 15:32 be called and that will go on until do 15:36 stuff is done and then we are the inner 15:41 core routine is done as well so the 15:43 first core team was stopped suspending 15:46 which means our own complete code can 15:49 just go after the collect and that's it 15:53 in the latest version and one that we 15:57 milestone to there's also an completion 15:59 operator which is similar to do one 16:01 complete from our extra which lets you 16:04 do completion and being inside the 16:07 stream if you prefer that style of 16:10 declarative programming okay next let's 16:15 take a look how an operator can be 16:19 implemented so now we're going to 16:20 implement the map operator which is I 16:23 think everyone who has used the Catlin 16:24 standard library or most of us have 16:26 already been used to separator 16:29 it's like mapping a value to another 16:31 value all those operators are already 16:33 part of the flow library itself but for 16:35 the sake of getting really understanding 16:37 what's going on we're going to 16:38 re-implement map now alright so let's 16:43 get started so taking our example from 16:45 before what we want to do now is we 16:47 still have this flow that emits every 16:49 every 100 milliseconds one value and we 16:52 want to map it in terms of what we are 16:55 doing is we are just multiplying it by 16:56 two and then the collect at the end gets 16:59 like the multiplied value okay all right 17:05 so let's take one step let's take step 17:09 by step now into what's going on under 17:11 the hood first let's start with actually 17:14 use another concept of Catalan which is 17:17 extension function so please note that 17:19 now we are going to introduce a map 17:21 function on the type flow okay so all 17:25 operators in flow or actually extension 17:28 functions 17:29 like that's really what's happening in 17:31 the in the library also let's take a 17:34 look at the transformer which is the 17:36 parameter that we get so we get a value 17:38 of T and we return a value of R in the 17:40 example that we do be it basically 17:42 mapping from integer to integer but we 17:44 could map from integer to string or any 17:46 other type of but and most important we 17:50 also return a float okay we return a 17:53 flow of our where R is like the result 17:55 of the mapping the type of the mapping 17:58 result so how do we get started writing 18:01 the separator so next step as we already 18:05 know we can create a flow by using this 18:06 flow builder and I want to highlight and 18:12 leave the brackets in blue here because 18:14 it's getting a little bit complicated 18:15 well not really complicated but harder 18:17 to read as we go on but this is now like 18:21 inside this blue brackets this means 18:23 flow collector okay just keep that in 18:26 mind I will highlight it later and once 18:29 we need it again so what we do next is 18:31 we want to subscribe to something or 18:34 observe something so we call collect and 18:36 collect is exactly the same thing that 18:38 we that Gabriel have shown before it's 18:40 like the flow collector dot collect 18:42 method that we can call sorry flow but 18:48 collect and this collect is referencing 18:52 to the flow and since it's an extension 18:54 function you may wonder but which flow 18:56 so going back to the example that we 18:58 gave that we that we showed you before 19:00 flow means the flow that gets returned 19:04 from this blue lines so we are actually 19:07 calling collect on that flow returned by 19:09 this by this by this builder like the 19:11 for loop alright so the question is how 19:18 do we get the value from here to the 19:21 next thing yeah it's exactly calling 19:23 collect collect is doing that and emit 19:25 is kind of pushing it and collect is 19:27 receiving it 19:27 that's why inside the map function the 19:31 map operator that we are going to write 19:32 now we call collect and we get the value 19:35 in other words we subscribe to this for 19:38 builder that was the first part of this 19:40 example inside the second part which is 19:42 the map 19:43 all right next what we have to do is 19:49 basically calling the transformer with 19:51 the value that we get so we get like the 19:52 value one we call the transformer with 19:54 it we get one multiply that 2 out of it 19:57 and that is our and what we do now is we 19:60 have to push this value down to the next 20:03 thing in our chain which would be then 20:04 the collect that just prints out the 20:06 value and how we do that by calling emit 20:09 and the mid is now in is now that the 20:13 the function that also gave a short 20:15 before that is part of the flow 20:17 collector interface so this is literally 20:19 flow it's just these two interfaces 20:21 which allows us to collect something and 20:24 to emit something and this is how we 20:28 push the value from here to the next 20:31 thing in the chain which is to collect 20:32 itself where we just print it so 20:35 operators or still just observe a 20:39 pattern so there is no difference 20:40 between what we have heard before how we 20:42 observe things and operator they are the 20:44 same in terms of the same idea so 20:49 getting a slightly more complicated 20:50 example 20:51 who knows what's which map is please 20:54 raise your hand 20:54 all right quite a couple of people just 20:58 to give you an example what it does or 21:00 what it would output this switch map 21:02 instead of in contrast to a flat map 21:04 would cancel any ongoing transformation 21:09 or job once you get a new value emitted 21:13 so in the middle in the middle of this 21:15 example we see switch map and we create 21:17 there a new flow and whenever we get the 21:20 value one from from upstream it will 21:25 start a new flow and it will print out 21:27 first value 0 and then it will wait 500 21:31 milliseconds in the meantime we get from 21:33 upstream and other value 2 and this one 21:36 will now cancel the previous flow that's 21:39 why we don't see any second value as 21:41 output in this black box which 21:43 represents the outputted value ok so 21:46 this is kind of switch map let's see how 21:48 we can implement this so again switch 21:52 map is already part of the standard 21:53 library just for the sake of 21:54 demonstration and 21:56 I'm going to implement this again with 21:58 you so this is our method signature 22:02 right so we have similar things like we 22:05 have shown before with map we have it as 22:06 an extension function we get this mapper 22:08 but now the mapper returns a flow of R 22:11 instead of just R that's the main 22:14 difference to notice now how do we 22:16 create a flow well again we use this 22:18 flow builder we have to collect to 22:22 subscribe to whatever comes from 22:24 upstream and now we're like we have the 22:26 value from upstream what do we do with 22:28 that value well we have to pass this 22:32 value somehow downstream right so we 22:36 only have focused now again on what's 22:38 coming from upstream but the question is 22:40 how do we pass that value from here 22:42 downstream so in other words what we 22:46 have to do is now get the new flowable 22:49 that is inside the switch map by calling 22:51 this mapper function and now we have a 22:54 flow of Type R and now we have to 22:58 subscribe to this new inner flow okay so 23:02 I know it's getting a little bit 23:03 complicated so you probably would like 23:05 to check it out later again on your own 23:06 in the slides that we are going to 23:08 publish but what we do now is we have 23:11 this inner flow that Scott's created 23:12 from this mapper function and now we are 23:15 subscribing to it to get the values out 23:17 of this and now as a next step 23:21 oh yeah first we have to launch it 23:23 because what otherwise it wouldn't 23:26 wouldn't start right because it's a new 23:27 flow it's a new kind of thing so we have 23:29 to launch this new thing by calling 23:31 launch which then starts a new color 23:33 teen and now that we have the value we 23:37 can emit it and emit now refers to the 23:40 flow collector the blue one from there 23:42 from there from their parent so to speak 23:46 does it work yet not fully bare cry 23:49 we're almost there so now we if it would 23:51 leave it like that we would have 23:53 basically flat nap because we never 23:54 cancel it whenever a new value comes in 23:56 to cancel whenever new value comes in we 23:58 kind of have to be we kind of have to 24:01 track the job from this inner flow so we 24:04 take this inner flow save it into a we 24:06 call launch and it launch returns a job 24:08 we save this 24:09 job into a variable and whenever we get 24:14 a new value in it's as easy as call 24:16 cancel on the previous job if there is 24:18 any previous job there is one more thing 24:22 that is important which is we also have 24:26 to what we only can call launched inside 24:28 a scope that's why we have to create a 24:30 new scope by calling this method 24:33 co-routines go we basically create a new 24:35 scope by taking whatever the parent 24:37 scope is right now and then we can call 24:40 launch and this is a switch map and this 24:43 there is nothing simplified also before 24:45 in the map there was nothing simplified 24:47 it's really that piece of code that is 24:50 also actually baked in in the flow 24:51 library more or less like the map is 24:53 pretty much one to run the channel that 24:56 the switch map is a little bit more 24:58 simplified here but it's working like 25:01 this composite works in there flow 25:04 library itself it's probably a little 25:05 bit more optimized by using some more 25:06 synchronizations mechanisms and stuff 25:08 like that inside but the main idea is 25:10 still the same and that would also work 25:12 perfectly well so let's take a look at 25:17 threading but before we can do that we 25:20 will actually need to take a look at two 25:22 concepts from the curtain library which 25:24 we saw already to some degree the first 25:28 one is the co-routine context a context 25:32 curtain context consists of multiple 25:35 elements which are also current in 25:37 concert text themselves we will take a 25:41 look at two of them because those are 25:43 the most common ones and the ones that 25:45 are most relevant for us right now the 25:48 first one is job we just saw job it was 25:53 used to cancel the inner core routine 25:56 and that's the main use case for us now 26:01 it does a lot more internally and fork 26:04 routines themselves but we will just 26:06 ignore that here the other context is 26:12 the curtain dispatcher it basically is 26:16 like a scheduler in our extravagance 26:19 where your curtain runs the library has 26:23 a bunch of dispatchers picked in so 26:25 there's a main dispatcher which runs on 26:27 Android on the main threat there's a 26:30 default dispatcher which is a threat 26:31 pool and that dispatchers used by 26:35 default if you don't have any other 26:36 dispatcher specified in your context and 26:40 then there's some more like IO which is 26:43 a stateful phone talking work or the new 26:45 singer threat context which just gives 26:48 the new threat and as a set of contacts 26:52 consists of multiple elements so you can 26:54 just combine multiple ones with a blast 26:57 operator and that's usually what you see 27:03 you have a job to cancel the context and 27:05 a dispatcher to determine where it's 27:08 executed the second context the second 27:12 concept is the coroutine scope it 27:16 basically just holds a reference to 27:18 context and that the interface itself it 27:22 has a bunch of sanction methods on it so 27:26 for example there's cancer which will 27:28 then just cancel the job inside the 27:31 context of the scope and the other one 27:35 is launch which we already saw there are 27:39 two baked in current scopes already in 27:43 the end Reigate xkx libraries there's 27:46 view model scope which Shanna's already 27:48 showed it uses the main dispatcher and 27:50 the job that gets cancer in on cleared 27:52 of the view model and the other one is 27:54 on life cycle which also uses the main 27:57 dispatcher but it gets canceled in the 27:59 ondestroy of the life cycle so that's 28:04 like actually that's writing we have in 28:08 scope on the lifecycle we use launch 28:11 when started which is similar to the 28:14 regular lounge but it will only get 28:16 executed once your life cycle reaches on 28:18 start and then we have the flow inside 28:22 it will just do some expensive operation 28:25 omit ins then the first map will 28:29 increase the end by one then we will 28:31 convert it to string and another map and 28:35 in the end we will print it out so where 28:37 does all this rotten like asset 28:41 co-routine scope uses the main threat so 28:43 that's probably involved and indeed the 28:47 print will run on the main threat the 28:50 maps will also be executed on the main 28:51 threat and since we're not doing 28:53 anything the expense of operation as 28:56 well which is kind of what we don't want 28:58 and the anti-pattern we showed in the 29:03 very beginning of this talk so how do we 29:06 get off the main threat here one example 29:12 would be to just use a different scope 29:15 that has a different context so it runs 29:17 on another threat so for example global 29:19 scope always has a different context and 29:23 we could omit there and we get off the 29:26 main threat and observe it there in 29:29 theory another way would be with context 29:32 it's a quarantine method that just lets 29:35 you switch the context you're currently 29:37 in the problem with both of those is 29:40 that it will actually result in an 29:43 illegal stay exception when you call 29:44 omit because flow has this constraint 29:48 that your emissions have to have to be 29:51 done on the same threat or the same 29:53 context as the one you were called on so 29:57 we cannot change the we cannot omit on a 30:01 different context and we cannot 30:03 influence the context of the downstream 30:07 so we cannot actually do anything in 30:10 here directly to get off the main threat 30:14 at least not directly 30:16 so one way to actually do it would be a 30:22 different order 30:23 it's called channel flow internally that 30:27 one uses a channel do this in this case 30:31 is not a flow collector but it is a 30:35 producer scope which comes from 30:37 coroutine channels and instead of emit 30:40 you call sent what happens internally is 30:44 that the channel then will 30:48 switch context from the i/o context 30:52 you're in right now when you call ascent 30:54 to the original context which would be 30:56 the main context and then call omit 30:60 there so in the end the main threat 31:03 would still be there for the maps and D 31:07 collect but the lambda inside the with 31:12 context would be executed on the main 31:13 threat so which is what we want this is 31:17 not what you would usually do though or 31:20 not encounter that often in the real 31:22 world because usually you just get a 31:26 flow some from somewhere like from a 31:29 database and you want to observe it and 31:31 you don't actually control the bidder so 31:34 how would you do that still the same 31:38 example there's an operator called flow 31:41 on and we'll call it with the IO 31:44 dispatcher so what will this look like 31:48 we have IO threat now and the main 31:52 threat so println and the lower map will 31:57 still be on the main threat because 31:59 flow-on is above it and like I said 32:02 before you can't actually change where 32:05 downstream emissions happens so there's 32:07 nothing nothing like Eric's Java observe 32:09 on and you couldn't even implement it if 32:13 you would want to and then the upper map 32:17 and the expensive operation would be 32:20 executed on the IO thread then if we 32:25 take the example again and just add 32:28 another flow on to make it a bit more 32:30 interesting and have three different 32:32 context now we have default below the 32:36 first map and IO for the flow on so 32:42 that's what it will actually do so map 32:45 will be caught on the lower map will be 32:50 so-called on the main thread as well as 32:52 the print the upper map will be caught 32:57 on the 32:59 default context and the expensive 33:02 operations still on the REO threat so in 33:07 summary the collect lumber is guaranteed 33:12 to be always called on the context of 33:15 your scope that you launched it in 33:17 initially so you will never run into the 33:20 problem like you do sometimes in our 33:23 extravagant observable and you don't 33:25 really know where is it executed on do 33:27 any trade and observe on you are 100 33:30 percent sure it will be run a your code 33:33 will be run and your context unless you 33:35 actually add a flow on and the flow on 33:39 will only influence the upstream so it's 33:42 also not like subscribe on which will 33:43 when there's no other operator like 33:47 observe on later on will go up and then 33:50 down again and the third thing for the 33:54 summary is nothing really nothing can 33:57 change the context of a downstream 33:59 omission so max some useful ap is that 34:06 you might find useful in your daily work 34:08 now that you feel comfortable with all 34:10 this context and flow and stuff like 34:11 that right so let's see how we can use 34:13 it in our daily work we can use 34:15 something like flow off which is similar 34:18 to our extrav us just or something like 34:21 that right so if you would create a 34:23 flowable that emits one two three four 34:24 that's what you can use for or you can 34:28 use just or create just a list and call 34:30 an extension function as flow on it or 34:32 the same thing for our sequence you can 34:36 also convert functions like this one to 34:39 a flowable or a suspending function 34:44 there were also packages or there's an 34:46 additional artifact or an additional 34:48 package that helps you convert from 34:50 Eric's Java to flow and vice-versa so if 34:52 you have like an observable from Eric's 34:53 Java you can convert it to a flow by 34:57 calling as flow on it and the other way 34:59 around you may you don't have to take 35:03 like one in step in between which is 35:06 calling as publisher which transforms to 35:09 a flowable from Eric's Java which is 35:12 implementing the pub 35:12 interface which is one of the reactive 35:14 stream specifications interfaces and 35:17 then you can call to observable on it 35:19 which is part of the flow library or if 35:20 there's additional flow to alex java 35:22 library there were also a lot of 35:25 operators that you already familiar with 35:28 if you are using our Xterra so for 35:29 instance subjects are still there kind 35:35 of in the flow library by using channels 35:36 our channels dot s flow to get a flow 35:39 out of it flat map is there is a flat 35:42 map from our java is there in flows it's 35:44 just called flat map merge con cut map 35:47 is called flat map conquered switch map 35:50 is still called switch map so that's 35:51 that's the same and some other useful 35:54 operators are there as well like map 35:56 filter retry zip combine latest takes 35:59 can reduce and a bunch of others that I 36:02 didn't put over it on that slide but 36:04 more or less the most common ones are 36:07 also available on flow or the most 36:10 common ones from Eric's job are all 36:11 available also on flow one other example 36:14 or real-world example would be to make 36:16 something like an HTTP request and in 36:18 oryx Java you would use something like a 36:20 single but in the code teens are 36:23 coupling world you have this convenient 36:25 suspend thing right and with retrofit 36:28 2.60 you have built-in support for 36:32 suspending function as well so now that 36:35 we have this suspending function to get 36:38 a book the favorite book of the user 36:40 let's see how we can use it in a flow so 36:42 let's say we have a flow that emits two 36:44 times the ID of the user so what we 36:46 would like to do is like grab now the 36:48 book of the first user and print it out 36:50 so we have something like this some 36:52 operator and we will we will see what is 36:54 some operator is in a second but what we 36:56 would like to have is something like 36:57 that we just call this get favorite book 36:60 right we get the book back and then we 37:03 just print it out or do whatever we want 37:05 to do with the book the question what is 37:08 this some operator any guess so how 37:13 would you do that in now it's Java now 37:14 it's Java you would have like a single 37:15 and you would have two flatmap a single 37:17 into an observable or something like 37:19 that right where flow it's just a map 37:22 why because map or the lambda that you 37:24 pass to the map is a suspending 37:26 and suspending function can cause 37:27 suspend a function so no flat napping 37:29 required or something like that to 37:31 achieve exactly what we want so to sum 37:35 it up flow is like this rx Java 37:38 equivalent to event streams but it's 37:42 baked on care routines which also adds a 37:45 lot of other nice benefits like writing 37:47 their their the on operator as they've 37:49 seen before 37:50 all right the switch map was probably a 37:52 little bit complicated but the map 37:54 operator I think that is something that 37:56 that feels natural also by using this 37:58 builders and stuff like that 38:01 Alex Java is working quite similarly 38:04 under the hood so there isn't that it's 38:06 exactly the same idea of our own server 38:07 pattern and you observe something from 38:09 up streams to get the value somewhere 38:10 below and then you call something from 38:12 the next observer to get like this chain 38:14 working that's still the same thing some 38:18 other benefits that you get out from 38:19 co-routines is like back pressure which 38:21 we didn't cover fully yet in this talk 38:25 and we don't have time to do that but 38:28 with the design of quarantines and 38:30 suspended function there is already back 38:32 pressure baked in so there's that is 38:34 nothing that you have to do in inside 38:37 your code as an author of an operator 38:39 for example well as it now extravagance 38:42 or to a certain protocol and so on so 38:44 this is kind of a little bit easier to 38:46 write when you compare writing operator 38:48 sinorix Java versus writing operators 38:51 were flow and that's basically it so now 38:56 that we have one or two more minutes do 38:58 you want to sing us that song now yes 38:60 not really okay but we would take some 39:04 more questions if in case you have some 39:06 questions there were some microphones 39:08 [Applause] 39:11 [Music] droidcon News Tech Showcases, Developer Resources & Partners /portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/home-details/EmployerBrandingHeader EmployerBrandingHeader https://jobs.droidcon.com/ /portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/jobs-droidcon/jobs.droidcon.com jobs.droidcon.com Latest Android Jobs http://www.kotlinweekly.net/ /portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/kotlin-weekly/Kotlin Weekly Kotlin Weekly Your weekly dose of Kotlin https://proandroiddev.com/ /portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/pad/ProAndroidDev ProAndroidDev Android Tech Blogs, Case Studies and Step-by-Step Coding /detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando /portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Zalando/Zalando Zalando Meet one of Berlin's top employers /detail?content-id=/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success /portal/rest/jcr/repository/collaboration/Groups/spaces/droidcon_hq/Documents/public/employerbranding/Academy for App Success/Academy for App Success Academy for App Success Google Play resources tailored for the global droidcon community