Kotlin Coroutines 101 – Android Conference Talks

hi I'm an old beaver I'm an Android engineer in the developer relations team at Google this video is about an introduction to curtains we will talk about the problems the curtains are trying to solve how do you score teens in android how to test them etc the first


thing we want to talk about is what problems are they actually trying to solve they basically simplify asynchronous programming on Android so whenever we talk about asynchronous programming we cannot forget about synchronous programming here we have the function load data which is going to display on the screen

the result of a net will request because this is synchronous it means that it will block the thread where this is being running on so imagine if we call load data from the main UI thread net will request will block the thread whenever it is waiting for the

mega request to happen and so in this case if the apprentice system is trying to call on draw that is not going to happen and therefore the user will see a frozen UI an unresponsive application you will get unblocked whenever the new request finishes and it calls show

as we can see let's see the definition of network requests here never request is there's a function that returns data and inside it we have the block Ian at the request code blocking the main UI thread is something that we shouldn't do in Android so how can we

move this net will request to a different thread how can we make it asynchronous a solution for this is using callbacks we have the same version of load data which is going to make the number requests on a different thread here as we can see we execute this

code we can see that nega request will be called and we will see later that the function mega request is going to be moving the execution of the nano request to a different thread and in this case the main UI thread is free and the trap apparatus is

tank on call on draw have refresh the screen as much as it wants when the never the network request finishes we'll call this lambda a callback there is going to display the result of the network request on the screen if we take a look at network requests now

just a function that doesn't return data more freedoms unit and instead it takes in a callback the lambda that we call in this case on success with what to do after the network request finishes we can call the photo scheduler dot executes to move at the execution of

the network request to a different thread and after that finishes then we can post to the main thread calling on success so while cool box might be ok solution for some news cases it has some problems first thing is that now this is a simple function that it

just makes another request and display something on the screen but now the logic can get complicated we can start adding a nesting Network requests after the other one happens and then we can add more more more and more stuff miss what becomes the callback help whenever there is

a lot of indentation error propagation might be difficult do you have hard coded posting to main thread whenever something happens and you might not want to do that it's complicated what if we could have the best of both worlds the simplicity of synchronous code with all the power

from a synchronicity and moving things between threads and this is where coroutines come in here we have the same function load data written with coroutines you might look a little bit suspicious you might think it will block the main UI thread but it won't the only difference that

we have is this suspend modifier in the function definition that's basically telling the cuddling compiler that this function needs to be executed within a crew team so how does it work how can never request not block them the dry thread whenever it moves to a different threat well

corrodens can suspend execution without blocking the thread and that's when I'm going to happen whenever we move to execute something to a friend thread so that's what we call the suspension point but also whenever that memo request finishes then we will resume execution so whenever the not go

request is done with whatever it has to do load data can resume execution and continuing with the result of that medical request if you take a closer look you will see that apart from that your request the rest of the function is that what we used to have

before as a callback so what is happening with the callback the coding compiler will write that callback for you under the hood when the computation can suspend actually corrodens called those callbacks a continuation continuation is just a generic callback interface with an extra information in it so how

is the compiler going to modify the function load data well it will take the suspend modifier and replace it by a parameter of type continuation and continuation form this state machine in which it will be executed depending if the function is suspended or not so we can say

that when it starts the function is starting will start with a state 0 when I really suspends will change states whenever it assumes it will be back to a different state and then we will finish this is what it's called continuation passing style and because it's quite a

complicated topic it is not gonna be covered in this presentation but as you can see there's a fancy way to say cool box so with corrodens computations can get suspended without blocking the thread as we said before back to our functional load data we're going to see what

never requests looks like in this case we will say that never request is another to spend function but now it returns data as the synchronous version of it how can the requests move the execution to a different thread all it uses with context with context is a suspend

function from the corrodens library that takes in a dispatcher as a parameter this patter is basically a way to say hey I want to run this computation in this particular thread in this case in IO and inside with context we can have our blocking map your request code

it doesn't matter if it's blocking the IO thread what is important is that it's not blocking the main UI thread what are these patterns that we have available we have this patters that IO but also dot default and this part may Allah is optimized to do Network and

disk operations they use default for CPU intensive tasks and main for UI code or non-blocking code that executes is quite fast so here never requests we can say that this is main safe you can call nebula request from the main UI thread and it will be ok because

it will be in charts to move the execution to a different thread so now we saw what problems called in are trying to solve it is simplifying asynchronous programming in android what good is according do you can think of a curtain as a runnable with superpowers if you

think about it it is going to take a block of code and it will be able to run it in a particular thread reliable carotenes is that a synchronicity can be expressed in a sequential way and that's going to be easier to read and understand it also called

it comes with other perks such as exception handling and cancellation there is typically more difficult to do with other persons for example callbacks backdoor functional load data imagine that we want to execute that whenever the user taps on a bottom for example we can have this function on

button click that will trigger low data but this is not gonna compile because the span functions must be called inside a corrodium we don't know how to create corrodens yet we will see that later but in a nutshell you can see we can use launch to trigger occur

routine so imagine that this works here some problems may arise for example who can control the execution of that Cora team does it follow a particular life cycle for example if the user is moving away from the screen can you automatically cancel it who is gonna get the

exception if that fails these are the questions that a structured concurrency trying to solve the structure concurrency is a design pattern system Corden's that tries to solve memory leaks and structured concurrency forces you to think about those questions whenever you are working with curtains I need by introducing

this new concept which is a scoped code in the scope coding scope is going to keep track of the codons it creates it's going to give you the ability to cancel them and it's going to be notified whenever a failure happens so now back to our function on

button clicked that will actually give another compiler error that's because launch must be called within a scope how can we create a corroding scope scope is that a simple variable that is really cheap to create it is not going to hold references to heavy objects so whenever you

want to control the lifecycle of a crew teen you can create a current in scope so in this case we can use this scope to trigger the computation and that computation will follow that coding will follow the life cycle of that particular scope so in this case if

load data throws an exception it will the scope will get that exception and will handle it in some way currents also create this hierarchy in which the root of the hair key it's going to be the scope which is going to be the parents of the other currents

that it creates so in this case for example whenever we don't need the scope anymore for example if we are in a be model when whenever we call unclear we can call a scope dot cancel and cancel my scope means that it will cancel all the children coordinates

that they started and it means as well that you cannot start more color things without the scope so with our function load data we can see that this was been function because it's suspend means that it has to be run inside a crew team it will run in

a scope and this is quite important if we take a step back and we think about synchronous code again you can see that when a functional returns it means that it has completed all work so imagine about the synchronous version of love data even it blocked a threat

it's okay but if return whenever he completed everything he had to do with corrodens is kind of the same when I suspend function returns means that it has completed all work and this is a very nice contract to have synchronous operations so now we're going to see how

to handle exceptions scoops can also take a job and a job is going to define the life cycle of either the scoop and also the curtains and whatever we passing a job to a scope that means that is gonna handle exceptions in a particular way when a total

fails it is gonna propagate the cancellation to other children I'm gonna failure it's not a fight the scope is going to cancel himself and propagate the exception up that means that in this case whenever load data fails you will not defy the scope that it failed the scope

will cancel the other children that I may have created before you will cancel them itself and will propagate the exception up in this case because we are now B model and there is nothing else in the hierarchy you will make your application crash but this might not be

desired in every situation for example here we are in a UI related scope and therefore we might not want that behavior so you can use the alternative with this supervisor job with a supervisor job if the failure of a child it is not going to affect other children

and so with the failure we know when a failure is notified the scope is not going to do anything so in this case load data if he throws an exception the scope will say okay I have this exception but it's not going to console other children but fYI

the exception can be propagated still so you may have to try catch it TLDR for structured concurrency when I suspend functional returns it means that it has completed all work when the scope is canceled it means that the children will be canceled too when the corrodium errors out

the scope will get notified and depending on the job you will behave in a way or another we're going to see how to create curtains now before we saw that we can use launch to do that but it is not the only way you can do it we

have launched an async a squall we are going to compare them with the similarities and differences between these two different approaches so set the first morality is that they can create a new curtain they can I start a competition where you can call suspend functions but D creates

crew deans with a different purpose so launch is going to create a curtain that is meant to be fired and forgotten so imagine that we have our login service where we can upload logs that have been in our application so we can use a scope the launch to

trigger that computation and that's it we don't care about it anymore let's launch a Singh is gonna create a new crew team that can return a value so for example we have this function get user that takes in a user ID as a parameter and it returns a

user object because we are now spending function we don't have a scope available so if we want to create a crew team we can use called in scope and inside here we can fetch our user with our user service and that computation can be happening in this passage

that idea for example so we have that and that is gonna a thing is going to return a different object and you can think of a third object as a future or a promise in jela and with that future or that deferred object you can call a wait

and I wait we'll wait actually we will suspend execution of decorating until async has finished doing its computation and we return the value of that curtain and this is what we return back to user another similarity as we saw it both of them take a spatter where do

you want to run that computation also both of them are executed in a scope launch an async our extension functions on the scope including the scope in this case and so in order to create one unit a scope they are not as to spend functions so launch an

async are the entry point to curtains how you can create a core routine so that you can call suspend functions but they are not suspend functions and they differ on the way they handle exceptions so launch is gonna throw the exception at sanity as it happens an async

is gonna hold on the exception until you call await we're gonna see more of that in a second so how you can handle those exceptions basically with a trackage here in our version of lunch we had before because login service can throw an exception you can wrap it

inside a tray cut and that will handle the exception thrown by the login service with a think is a bit different as we said async is not gonna throw the exception therefore you don't need to wrap it inside a try/catch you have to do it in with a

wait a wait can through the exception that happen in the async block of code therefore you have to wrap it inside wreckage and there you will handle that exception now we are going to move on to a different topic we have this coding on the screen that is

called with launch and it's going to happen in the in an i/o field so we have a for loop which is going to read files from a list what happens if we call scope dot cancel is that going to cancel the execution of that coroutine or not well

in fact it is not gonna do that because cancellation requires cooperation whenever you are doing something very expensive in this in this case we can spend a lot of time reading the files you have to cooperate and make this counselor work if you think about it the coding

or the thread is gonna be really busy reading files and it is not gonna be say be listening for cancellation so in this case you have to cooperate and check if the accordion is active or not and you can do that by checking for example or calling ensure

active or deal whenever the cord in is cancelled and that function is called then it will stop the execution of this coding so again if you are doing a heavy computation make sure that you check for cancellation we created a lot of functions throughout the presentation and some

of them were marked with suspense some others weren't when do you actually have to mark something as you spent all this is easy whenever it calls or suspend functions so remaining I will load data function we had before suspend function why is that a suspend function because it

calls never requests that is also a suspend function why is never request a suspend function well because it called with context and with context is a suspension that comes from the corrodens library this is the reason why but now when don't you have to mark it as a

suspend well whenever it doesn't call other suspend functions so on button clicked is as a function that triggers the curtain it calls lunch because a launch is not a sprint function on button click doesn't need to be either so the tip is don't mark a functions to spend

unless you are forced to and in this case do either market as a suspend or us start decorating as we did with a button clicked we're going to see how to test holidays now so testing asynchronous code is quite difficult because you want a deterministic behavior you want

the test to behave always in the same way and we're going to see different use cases for the different ways that you have to do that the first use case before those tests that don't trigger the execution of a new curtain so for example let's say we want

to test load data no data it is not calling async or launch it has to spend function is not triggering new curtains even though it is moving to a different thread with with context that is what Nega request is doing it is not creating a new curtain so

we are ok here this is the first use case you can test this using run blocking run blocking is a method from the curtains library there is gonna start accrue ting and it's gonna block the thread where it's been cold until everything finishes until the block of code

finishes so in this case we can create a be model instance called load data and load data is going to be executed synchronously and so we can make sure that the next line after load data means that load data has finished doing everything so now we can assert

that show did something that was quite easy right the second use case is more complicated and it for tests that trigger new curtains so for example we have my view model and we want to test on bottom clicked on bar down clicked is triggering a new computation is

triggering a new corroding calling launch can we use the same way as we did before run blocking well if we think about it whenever you call on button clicked it is gonna run a new Korra team and that kuru deenus might be potentially running on a different thread

and so it is gonna happen asynchronously so button clicked is gonna call launched and it's going to move on it's going to end the function so whenever you call assert it might be happening that the other coordinates is still running therefore it's not reliable you cannot use it

another way is waiting for something to happen so in mind that you update some results somehow a new wait for that we have a new value either having I call the latch or using life data this noodle is using like data or with mojito wait you have different

ways to wait for something to be there but that's a coda smell that's because the test is not going to be running fast might take a couple of seconds for something to be there and that's kind of a bad practice thing is that you might have to run

it sequentially as we did before with run blocking and how can you do that well basically is we can do that by forcing the Karoo team to run in a particular dispatcher and they would practice for this is injecting these patches so in this case for the view

model you can inject a spatter in the constructor and then use thus dispatcher to trigger the call team inside on button clicked and now in our test we can use that as scored in dispatcher we create this discovered in dispatcher instance that we are going to pass into

the view model so that curtain is going to be executed in this task or routine dispatcher and in the test inside of using from blocking to wrap our test body within it we are gonna use the function run block in test from the test dispatcher that means that

a recruiting running on that this patcher is going to be executed synchronously in that case whenever we call on button clicked it is going to execute that coroutine synchronously that means that whenever embattled Venus's means that the accordion has finished soon and now you can assert whenever she

did something without having to wait for that to happen but now imagine that on button clicked has to do something else before running the kuru team how can we test that well test quarantine dispatcher comes with nice functions to be able to post execution of quarantines and to

resume them so in this case we can call test dispatcher dot post dispatcher to assert that something happened before the curtain and then call test dispatcher that resume dispatcher to test what happened after the curtain run so for testing use from locking when the test doesn't create new

curtains and as a good practice inject dispatchers and you test in this pattern test whenever you want to that something that is going to trigger new curtains that's going to be the end of the video we went through a lot of stuff so we said what problems go

routines are trying to solve in Android which is simplifying a synchronous programming how we can move the execution to a different thread using these patters and with context what accordin is basically you can think of it as a runnable with superpowers how corrodens work under the hood the

coddling compiler will rewrite the suspend functions to use coal box the principles of a structured concurrency that is going to avoid memory leaks and is going to force you to think of who is going to manage the lifecycle of that coroutine whenever you are working with them how

to create coroutines and the differences between launch and async how do handle exceptions when to mark a function as a suspend or not and testing accordions and the usage of desk around in dispatcher if you are interested in more things about curtains I suggest that you go through

the different code labs that we have available we have two of them a basic whole lab and advanced code lab that uses life data crew team builder and more advanced topics if you are more interested in testing curtains there is a video at Android developer summit 2019 where

I give a talk with some and then for and exceptions another video in cut link of 2019 win Florina Moulton ESCO thank you for watching bye you.

Nhận xét

Bài đăng phổ biến