PARALLEL Background Tasks with Kotlin Coroutines (ASYNC AND AWAIT)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
in this video I'm going to show you how to execute jobs in parallel so how to execute in multiple jobs on background threads at the same time so like say you have a background so you have five background tasks and you want to complete them all at the same time so none of them depend on each other you want to start one two three four five all at once all at the same time and then print that results to your UI that's what that's the concept that I'm going to show you in this video using co-routines and just as kind of a heads up there's no technical there's technically no co-routine knowledge you need ahead of time to be able to benefit from watching this video although I do recommend watching my co-routines introduction video on my youtube channel so if you go to my youtube channel just go to the coding with Mitch click on the videos tab and if you scroll down and you'll you'll eventually come to this co-routines introduction video right here coddling co-routines beginner example Android if you watch that that should give you all of the knowledge that you need to benefit from this video but like I said you know even if you have no knowledge of co-routines that you could still watch this and definitely get something out of it so let's take a look at Android studio and I'll talk a little bit more about specifically what we're going to cover so in this video I'm going to show you two examples both will do the exact same thing so the goal here is to launch or to create two kind of background tasks I guess that you would you could think of it that way and the objective is to run the tasks get some results and then print that results to the log or the UI either either one is fine so I wanted to show you two different ways to do it because typically I get this question a lot when it comes to co-routines people are asking they ask about a sink and a weight if you've heard of that before they ask about using jobs and using the launch the launch what would you call it co-routine builder i guess you would call it and like how they're different and I'm going to show you an example achieving the exact same results using the two different methods so I want to highlight how they're pretty much the same it's just a different way a slightly different way to do things and one is better for one scenario and one is better for other scenarios okay so first let's just quickly go over the code for those of you who are just coming into this and didn't watch my co-routine introduction video I just have one activity and a layout file in here so let's just quickly take a look at the layout file this is activity main it just has a button that says click me the preview doesn't seem to be coming up here but I'll just bring the open to show up so it just says click me and then there's a text viewer just kind of in the middle of the screen there and so all it does is if you click the button we want to start a job and then print that results to the UI so we don't need to look at activity main anymore let's just look at main activity so here we have a couple of methods that have built ahead of time there's nothing kind of fancy going here the first method is set new text just text sets some string to that textview that I just showed you in the layout set text on main thread does the exact same thing but it ensures that the the UI is only updated from the main thread so we're using where it's a suspend function meaning it has to be called inside of a KO routine and it's calling with context and switching over to the main thread before setting that text so that ensures if this method was called on a background thread it would switch it to the main thread and then have to update the UI and we need to do this for those of you who know Android know this is a very common thing you always need to update the UI on a main thread if you do it on a background thread the app will crash and if we keep keep coming down the file here we just scroll down a bit we have two methods get results from API get result one from API and weave get result two from API and all these ARS or suspend functions so they have to be called within a KO routine they each have a delay in them one is for one one second or a thousand milliseconds the other one is for 1.7 seconds or 1700 milliseconds so you can probably guess what our demo is going to look like we're gonna execute both jobs or both of these methods both of these functions at the exact same time and I want to show you that we are able to execute them in parallel so the total job completion time will be 1700 milliseconds which is the time for the longest one to complete because they they're both executing at the same time all right so let's scroll up to the top here and first I'm going to attach an onclicklistener to the button I called it button very creative I know so I'm gonna attach an onclicklistener like this I want to set new text to the butt to the textview just saying clicked you know exclamation mark just to update the UI and say that yes we did click the button notice I'm calling set new text I'm not calling set text on main thread although it would be fine if I had called that inside of a KO routine but right we are not on a background thread so it doesn't matter we can just set the text now I want to launch a co-routine because we're gonna be calling a function to get the job process started off so I'm gonna write Co routine scope and reference the i/o dispatcher which is a background thread and now I'm gonna call dot launch to build a new Co routine and I'm going to call a function in here named fake API request we'll call it so obviously I haven't made that so I'm gonna highlight the this area click alt enter go to create function fake API request there is my function and now inside here we're gonna write the code to start these two jobs to get these results oh and we need to mark this as suspend because this is going to be called with co-routines inside of it so first I'm gonna write with context I'm I'm referencing the i/o dispatcher once again alternatively I could have just done this so I could have just left this if I delete this get rid of the suspend function I could have just launched this co-routine inside the function that would have that would have also been fine so we could do that what at whichever way you like either way you're still going to be launching a crow routine on a background thread which is which is the which is the overall goal here now first I'm going to create a job for the first result so I'm going to write value job 1 equals launch so I'm using a the launch builder to build a new Co routine I'm going to create a variable named time 1 which we're going to use to measure the time of each each job and how long it takes to complete so I'm going to call the measure time in milliseconds builder this is something you can only call inside of a Co routine and it's really handy because when it's complete we can then print out at that time so like down here I can do print line debug and I can write completed job 1 in whatever amount of time so time and then milliseconds so now inside here whoops this needs to be time 1 now inside here we can get that result from from the first from the first method get results from API number 1 so first let's write a log just to keep things really obvious and really clear so you see exactly what's happening so I'm going to write launching job 1 and then I print the thread so I'm going to write thread dot current thread that will print out the thread name or sorry the the thread and then I can get the name by calling name now I want to go to the next line get the results so value results 1 equals get results one from API so this is again just to kind of review where this is a suspend function it's going to delay so delay one second and then it will return this string result number one so that's what this is we expect that to say so now I want to get that result call set text on main thread and I can just say you know got results number one so result 1 so then that is going to set the text to that textview in the layout on the main thread because remember we're calling with context and then referencing the main dispatcher so that's job number one now I'm going to copy this and go to the next line paste that in and just change everything to job number two so job - time - we're gonna have launching job two in the thread get the thread name we want to go you know result to get results two from API and I want to get result two right here and also change time down here to time number one so now by default these two jobs will execute at the exact same time so this if you can imagine this fake API request function will be called it will launch this co-routine and then these two jobs independent of one another will get launched at the exact same time so I think it's it's pretty obvious you know there's nothing really fancy happening here there's nothing no surprises it's just sequentially executed code so therefore you know as soon as the method is called job one is gonna launch next job to let you know milliseconds afterwards that technically they're not launching at the exact same time because they're called sequentially but I mean it's you know it's going to be within a few milliseconds of one another so you could pretty safely say they're executing at the same time they're gonna be executing at the same time one is not waiting for another one for example if I was to do like job number one and call join then then that would be sequentially launching them they would no longer be launching in parallel because what what's that saying is it's saying wait for job one to finish before you proceed to the next line but we want them to launch at the same time so I'm gonna get rid of that so let's let's run this and take a look at the log and see what kind of output we get we can also take a look at the UI all right so I will open up the logcat here and I got the right device selected I'm going to filter on debug because I added deep to each one of the logs and I'm not sure why nothing's showing but let's let's see if anything happens here Sona click on click me there you can see down there it says launching job 2 and thread launching job 1 in thread this is actually so right here it says that they're using the same worker that's actually a coincidence they they actually by default what's happening is it's just pulling from a thread pool and using whatever threads are available so it's a pure coincidence that they actually here launching on the same thread but anyway so the most important part here is you can see oh it looks like I have a problem the way I wrote this but either way it says job 1 finished in 1,000 milliseconds this should be job - I just labeled to log in correctly so if I look in here this should actually be job 2 that would fix that problem so job 2 completed in 1700 milliseconds so both of them started and finished and they were executing at the same time I just paused the video and I went off camera because I realized what I'm just showing you here it's not really necessarily clear that both of them were executing at the same time so I want to show you a little something extra just to make sure that it's very clear to you that they are actually executing in parallel so when we create a variable up here called start time so start time equals you know system dot current time in milliseconds that will get the current time the co-routine will launch and I'm going to create a parent job so value parent job equals so this parent job it will have two children job number one is the child number one and then job two would be like the second child so once these two children complete that means that parent job would be complete so what I can do is scroll down to the bottom here and write parent job invoke on completion so when the parent job is completed this this code will run some write print line debug the total elapsed time is what all right here and I'll do the system current time in milliseconds subtracting our start time so that'll give us the total elapsed time to complete the parent job and in other words that would be the the sum of job one and end job two so that the total time that takes to complete job one plus the total time it takes to complete job - so you'll see here when we run it so I'm pressing shift f10 that to complete these two jobs it should only take 1700 mmm seconds meaning that they were executed in parallel so let me bring up the logcat here and bring the phone on the screen I'm gonna click the button there we get the two dispatchers we get completed job one in a thousand milliseconds completed job two in 1700 milliseconds the total elapsed time is seventeen hundred and sixty-two milliseconds so roughly the time it takes to complete job one so there you have an example where I'm running two jobs in parallel at the same time now I'm going to show you another example where I'm gonna do the exact same thing but we are going to use the async and await pattern so this is just another way to use co-routines it's not like another library it's not something totally different it's just different operators different builders that co-routines give us access to basically and I the reason I wanted to show you this is I get a lot of questions about you know launching co-routine starting co-routines using async and wait you know how do these things differ so I wanted to really really highlight that you can achieve the exact same thing one is just slightly better in you know this circumstance or that circumstance and the other one might be slightly better in a different circumstance and I'll try and highlight this this different kind of circumstance as I as we go through it alright so similar to the last one I'm going to I'm going to create a variable called execution time so this is the total time it's going to take to do the co-routine oh I actually need to launch the co-routine first I'm going to comment that out and do co-routine scope I'm in reference the IO dispatcher called launch to actually launch our core routine and I'm going to move that inside here and uncomment that so this execution execution time will be again we're going to measure the time in milliseconds so you can imagine that once this is complete we're going to print the line go debug and say total time elapsed just like we did before and just print the execution time so I don't I'm not going to need to use that get the system time in milliseconds here because of this different sort of pattern that we're using the async and await it makes it a little easier so when you're using async and a weight you get access to this thing called a deferred type so I'm going to write result 1 equals deferred I'm referencing the type which is a string because down here we are returning strings from our from our functions so I need to reference the string type if this was you know some custom class then you would obviously put some custom class there so setting this equal to a sink which is just it's just a Co routine builder very similar to launch so this is the same sort of concept as launch it's just building a Co routine but it's a Co routine with slightly different properties so you can see that it's giving me a warning here and that's because I've I've declared this as a deferred type which returns a string so I have to return some string like if I was just write some there or some string you can see that warning goes away because it would be returning that string but obviously we want to get that value from our function so first when it print the line and show the thread that this is executing on so I can say launching job one and I can you know print out the thread so thread thread current thread name just like we did before nothing different and I want to get that result so I can do get result one from API so you can see it's kind of it's a little cleaner I guess you would say as compared to the classic sort of job launch pattern now I want to do the exact same thing for result number two so again getting that deferred type it's going to be a string setting it equal to async again I will print the line just write debug launching job number two and do again thread dot current thread and then dot name so now I need to get that result so get result from get result two from the API and there we have both of our results so now here comes the second part of when you're using the async and a weight pattern so the second kind of part of using the async and a weight pattern is you need to call another function still to get the result so you can call it whatever way you want in a log when you're declaring a variable or inside of a method it doesn't really matter as long as you call it so I'm going to call set text on main thread and pass the the result so I'm just gonna say you know got the result in this case it's going to be result number one and I want to call dot await so got result number one and then that's going to print that to the screen so I want to copy that and do the same thing with result number two so the way this works is it works you know almost exactly the same as we as we had with the job launcher pattern right when this is called the this is going to execute and then this is going to execute you know milliseconds afterwards the only thing that's different here is that we need to then call a weight to get the result there's no way to get the result from what you executed inside here until you call a weight so when I call dot await this will basically just sit here waiting for the result as soon as it gets it it's gonna print it same with this that you know it's it's exactly the same it's going to sit there and wait for the result as soon as it's there as soon as that function is done then it will print it so you'll you'll see the exact kind of same behavior so I'm gonna press shift f10 to take a look at this and we'll see see what it looks like in the log all right so press click me then we get clicked both of them are launched as you can see and it says total elapsed time is 1700 milliseconds I actually I wasn't looking over here so I want to launch that again so if I click it notice get result 1 get result 2 so you can see they come in in stages the results number 1 comes in after one mill 1 1000 milliseconds result number 2 comes in after 1700 milliseconds and the total elapsed time is 1700 milliseconds so actually it's it's slightly better I think because the other one was 1756 so this one's you know slightly more efficient very marginal but still you know slightly more efficient so now kind of the most important thing about this or the question you probably have right now is okay they do the same thing so what which which one should I use pretty much and I would say that the the main I think that the job kind of launcher pattern is seems to me like more intuitive I guess the async and a wait pattern is slightly less intuitive but I mean I mean I think these things just come in practice so the only real difference is that the async and a weight has the advantage that you can get the result right here so like right here I have the result from the value as opposed to the job pattern that result is stuck inside the co-routine so if you remember you know just to kind of give it just kind of review you'd have job equals you know launch and then I would have you know value result equals get results from API so that result is stuck inside the KO routine whereas with the async and a weight that result is accessible outside of those co-routines right here so I don't have to like really if you were to do this and you wanted to get the result outside the co-routine you would have to do like var result equals empty and then inside here you know set result and then I would have access to the result outside like then I could print result here whereas with the async and await it's very streamlined it's already kind of done for you so if you need a result outside of your Co routine the the better way to do it is using a sink and a weight because all of that is kind of packaged together if you if you use the job kind of launcher pattern which is seen by this right here you don't have access to that result really out of the box you have to you know create a variable set it equal to blank get the result and then get it afterwards so you know I mean it's it's whatever oh you know and also you would um you'd have to do job join because you have to wait for that result if you printed the result right away it would just print a blank string so all of all of this kind of stuff is nicely packaged with a sink and a weight all right so that's gonna be it for this example you know I just wanted to quickly show you two different ways to do the same thing and clear up any confusion around you know a sink and a weight and how it compares to the more kind of streamlined or classic way of doing things with you know just creating a job and launching it and that kind of thing so hopefully this helped again if it helped leave it leave a like if you liked these co-routine videos leave a like if you want to see more co-routine videos or a specific topic around Colin or co-routines leave a comment I always read the comments you know if enough people want me to do something inevitable II I almost always do it I also want to say a special thanks to all of the new members who recently joined on coding with Mitch comm I did a 20% off sale the other day and it went really well trying to advertise the new powerful Android apps with jetpack architecture course where I talk about Colin mvi architecture live data and view models navigation components which is the new way to navigate with fragments on Android which is absolutely awesome I love it the rune persistence library co-routines retrofit to dagger to and arrest API integration all kinds of topics a really great course I really wanted to make sure that lots of people were going to get the chance to to take a look at it so thank you again everybody and I look forward to talking up to you about it in the community discord Channel I'll see you in that next video you
Info
Channel: CodingWithMitch
Views: 22,977
Rating: 4.9770775 out of 5
Keywords: async await kotlin android, kotlin coroutines, kotlin coroutines tutorial, kotlin coroutines flow, kotlin coroutines android, kotlin coroutines android example, kotlin coroutines android tutorial, android coroutines, android coroutines async await, android coroutines tutorial, android kotlin coroutines, android kotlin coroutines tutorial
Id: HPpiPzwQ_cU
Channel Id: undefined
Length: 20min 18sec (1218 seconds)
Published: Mon Oct 07 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.