Kotlin Coroutine Jobs (Beginner Example)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
all right welcome to another video about Collin co-routines and this one I'm gonna talk about one of my favorite things if not maybe even my most favorite thing about coddling co-routines and before I talk about it let me paint a picture of a situation that caught this call and co-routines feature solves it's a situation that comes up all the time in android development so let's let's talk about here it looks like my volume is in quite high enough so so let's take a look at this demo application here this is the one we're going to be building in this video it's a very simple app when I press the start job button a progress bar goes ahead and goes all the way to the end if I let it go to the end it says job is complete so it updates the UI if I cancel job it restarts and you get a message saying resetting job if I was to start the job and cancel it midway through I get that message resetting job and the job is reset so this might seem very simple but let me talk about kind of commonly when you would encounter this sort of situation so here I am in the jetpack documentation or the jetpack section of the Android documentation this is where they talk about the kind of recommended architecture for your applications specifically I believe they mentioned mvvm so you have your activity your view model your repository and you have your two data sources you could have many different data sources but in this example you have two you got your room persistence library and your remote data source which is just basically accessing the internet your asacs accessing a REST API whatever so what happens very commonly what happens all the time is you go into your repository you go to make a request and say you're making a network request and for some reason the network is slow it doesn't matter what the reason is and you need to cancel that job so you have a timeout maybe it's three seconds four seconds whatever you want to wait and then you've got to cancel that job in the in the in the past this was always very difficult to do if you're using async tasks this was very very difficult because async task is basically it's it's not useful you should not use that anymore if you are currently using it you have executor x' which is kind of a little better but still it requires a lot of code to be able to handle when to execute the time-out what to do the time what happens how to send how to update the UI afterwards all that kind of stuff requires a lot of code and it's it's a pain basically and then coming up you have rx Java arc Java again makes it a little easier actually it's quite a bit easier because you can just apply operators you know say after this amount of time do this thing if there's an error do this thing if the time one occurs throw an error there's all there's more options and it's it's a lot easier so now we come to co-routines co-routines even take it a step further they make it even easier and I have to say I I continue to be impressed by co-routines as I'm kind of learning them as I'm going through them as I'm getting better and better at calling and this feature is it's really awesome so I've got a very simple example lined up for you as I showed you with the starting job job cancellation thing but it's a it's a good one I really really think you'll get a lot of value out of this so let's without further ado let's get into the example all right so first I'm going to take you through the code that's existing in this project you can create a brand new project if you want there's really I'm starting from basically nothing in this project at all activity main is really the only thing that has anything just a constraint layout with a linear layout below it vertical orientation I got a progress bar a button in a textview so that's all there is in this code is going to be in the description of the video if you want to copy and paste it or you can just kind of watch along and not do the code yourself but I always recommend using the code it's always better to kind of follow along than to just watch so what do we what are we trying to do here well we want a onclicklistener on our button so if I pull up the application we want a none click listener on our button and then when I click it we either start a job or if I click it again we cancel the job and we give kind of a reset message there so let's let's start by creating some variables so I'm gonna declare a bunch of constants first of all private value it'll be progress Max equals 100 that's gonna be the maximum progress allowed for the progress bar progress value progress start equals zero private Val and then the total job time so is gonna be the total amount of time that the job takes to complete it's gonna be four thousand milliseconds and then I'm gonna use a late in it variable I'm gonna call this job and it's going to be a completable job object so this is a Kotlin co-routine object there's a it's subclasses the if we click it here its subclasses or sorry it extends by jobs so it is technically just a job object the difference with a job object and a completable job object is a job object has kind of more features added to it and you might have guessed that obviously because it extends job but let's take a look at some of these other features you have complete and complete exceptionally these are kind of the two main things that I'm interested in complete will return well you can read the description over here it says completes this job the result is true if the job was completed as a result of the invocation of this method and falls otherwise so if I call job complete that will complete the job it will mark the job as complete and then the other method that I was talking about was complete exceptionally so completes this job exceptionally with a given exception so those are the two things that make that kind of make this job this completable job objects stand out from regular job objects and it's really nice because basically what it gives you is it gives you the ability to complete a job on your own terms so you decide when this job is complete you don't let the co-routine decide when this job is complete that's kind of the biggest thing so if you're doing any kind of a operation any kind of a request having the ability to complete the job when you decide or not is a powerful thing so what's next here well we need we need to have a way to start this job up so let's go down I'm going to create a new function named an it job and inside of this I want to first do job button which is the ID for the button in the layout the button that starts the job I'm going to say set text and this is going to be start job number one I can just say start job it doesn't really so our job or start job number one next I want to update the textview to be blank even though it will already be blank but for now I'll just kind of write what is the textview it was job complete text I'll do set text and just set that to blank I'm gonna create a method for doing that later but just for now I'm going to set it just set it manually like this now now the next step is going to be creating actually creating this job so job equals new job basically what I'm doing there because this is a late in it we do need to make sure that we initialize that so what what late and it means if those for those of you who don't know it means that this this object is not initialized yet so if I was to go inside of on crate and do you know job complete it would throw a null pointer exception because that job is not initialized yet that's why I need to make sure that I initialize it which is what we're doing inside of the init job method so next I want to do job dot invoke completion invoke on completion so this is this is one of the best things this is one of the best features about this job sort of pattern I guess you would say so as I outlined at the beginning of the video one of the most common things that happens is you you you know wave for a network time out for a job if you're making a request something happens doesn't matter what it is you have to either complete or cancel the job and then you need to update the UI accordingly once that job is complete so that's what this is going to do that's what this allows us to do it's called invoke on completion so whether the job is canceled or completed this code will execute so then inside here we want to basically update the UI we want to let the user know what's going on was a job canceled is it still happening it was there an error whatever the point is we need to update the user so I'm going to write it dot message so if the throwable if there is an error I want to get the error message so if for those of you who aren't familiar with this Kotlin notation basically it's saying check for null if it's not null get the message and then we can do something so let's take a look what we're going to do so we do variable message equals it it's going to be the string message from that throwable object and then if the message is null or blank because it can be null you can see up here from the description it can be optionally null you can see with that question mark that question mark means that that string can be null so if it's null or it's blank then I want to assign a message so unknown I'll say unknown cancellation error because we still need to let the user know even if there's not an error message we still need to tell them that something went wrong and you know tell them whatever let them know so let's do print line and I want to add in that exception so first I want to do job I want to print out the jobs to the log the one that is currently being executed I'll say job was cancelled and then I want to give the reason so the reason is the message and then of course that will print to the log but we need to let the user know so what we're going to do is we're going to create a method named Show toast so fun show toast it's going to take text as input that's going to be a string a string that cannot be null and I want to write toast make text and the context of this is going to be this at main activity main activity I'm writing main activity for a reason so some of you are probably confused why I'm writing main activity obviously this is referring to main activity but there's a there's a there's a reason for all this so just hang on your toast dot length short and then show so the reason why I'm writing this at main activity is because we don't know if like I want this show toast method to be able to be called inside of a co-routine inside of invoke completion I wanted to be able to be called from wherever I want so I'm gonna I'm gonna create a new Co routine using the global scope here that way I can call this method anywhere I want and I know that the show toast method is going to be called on the main thread so I'm doing global scope which is a co-routine scope I'm writing launched on main so and then I'm going to call this inside of here so no matter what if this is called inside of inside of a KO routine inside of my invoke on completion no matter what this show toast method will be guaranteed called on the main thread and that's because that's where the toast is going to be shown so that's very important and it's giving me a warning I believe because I wrote a capital T there so this at main activity so there we go there is our show toast method I'm going to come up to an it job I'm gonna write show toast and inside here I'm going to write the message so just passing the message so that will initialize our job and also if our job is completed it will get any error message that's associated with that and it will update the UI and let the user know which is often you know the most important thing you always got to let your user know what's going on having an error is not the end of the world it happens but definitely if you don't tell your user what's going on you're probably going to piss them off and they are probably going to uninstall your application so now the last thing I want to do inside of an it job is job progress bar dot max so I'm setting the max value that's going to be the progress Max and then job progress bar the progress will be the progress min so progress our progress start so that kind of that kind of resets everything that's going to create a new job handle the cancellation or it's going to initialize everything and then reset the progress bar so that there is a Max and there is a current progress value so next is an actually calling this initialization initialization method so I'm going to do job button and set an onclicklistener set on click listener it's just going to be a lambda function and then inside here I want to check if it's been initialized so if job dot is initialized this is how you check for initialization of a late and knit value which is our job object if you scroll up you see that it is a late and knit variable so I'm checking if it's initialized I'm not checking if it's null I'm checking if it's initialized this is a unique property to late init objects and so if it is not initialized I want to initialize the job and that's going to set up our job create a new one all that stuff that we need to do the next part of this example is going to be handle the starting of the progress they're starting the job basically so this this and NIT job method will create the job that's all great but how do we actually start the job and start that progress bar going to the end and then also handle that cancellation so the next method that we are going to build is going to be for that so I'm going to create a new one named fun and it's going to be an extension function on a progress bar so I'm going to write progress bar dot start job or cancel and it's going to take a job as input which I should have written in there so coming back up here it's gonna be job job and inside here as you might have guessed it's gonna be responsible for either starting the job if it has not been started yet or canceling the job if it is currently in progress and for those of you who don't know about Kotlin extension functions all this is is I'm saying here's a method I'm gonna be able to call it on a progress bar if I call it on a progress bar I can then access that progress bar by writing this so see if I write this it tells me that I can access that progress bar and then I can set the progress I can set the max I can do whatever so another really cool feature about Colin if you didn't know that it existed so how do we check if the job is already started or if we need to start a new one so I'm going to write if this which refers to the progress bar dot progress is greater than zero then we know that the job has already been started so I can write print line I can tell the user or I can tell the debugger this job is already started or already active let's say already active because that's technically the status of the job and I can say canceling because if it is active then I want to cancel it and in case you were wondering I just used some terminology that you might not be familiar with so I said is if the job is active or is cancelled so if I do job dot and you can take a look at all these different statuses so this is active is completed is canceled so what I'm looking for is if the job is active so that's what I'm saying here job is already active in that case I want to cancel it so we can come down here and call reset job which is a mess that I haven't created yet but that's going to be responsible for actually resetting the job so I'm going to write alt or click alt enter on there and go to create function reset job and I'm gonna come back to this I'm not gonna fill that out yet we're gonna continue with our start job or cancel but I will come back to that and that's going to be responsible for resetting the job so that everything is basically at square one again okay so otherwise if that job has already been started I want to do job button and set the text to the job button so set decks set text cancel job number one so that's if we take a look at the demo application you have start job number one cancel job number one that's the text that were setting right here so after that we need to fire up our KO routine because remember this else statement denotes if our Co routine has not started yet so we need to start it up so in right co-routine context or sorry Co routine scope and here is a very important this is a very very important thing that you need to pay attention to about starting jobs and yes starting jobs in general and different scopes for different jobs so imagine a curve 18 scope is a scope I can pass you know I can pass main in here I can I can pass IO I can pass whatever it is the dispatchers default a bunch of different options typically you've probably seen me in my examples pass IO because that is a background thread and then I would do you know dot launch and I would launch that co-routine and this stuff would be executed on a background thread which is a magical thing that co-routines do but what we are going to do here is we want to tie this co-routine scope into the job so it's kind of like you create this co-routine scope and then within that scope you're adding different jobs to it so inside here I can actually do plus job and what that does is it adds the job to this court in scope and creates a brand-new co-routine context independent of any other co-routine context so like just as a example if I had another job say it was job number two I could do il plus job number two and that would be a totally in dependent job if if I called cancel on this job it would not interfere with this job that's running and if I called cancel on that job it would not interfere with the other job that was running so this is a very important thing because if I was to so say I started this co-routine scope and I wanted to and then later I cancel it so like let's see I'll just say coat I'll do value scope equals this and then do if I was to do scope cancel if I had any other jobs that were running within the IO what would you call it io context I guess you would call it if you had any other jobs that were running an IO like I said earlier if I had another job co-routine goroutine scope and it was running on IO and I had you know launched and something else was happening in this one if some whoops this needs to be a capital so if I called scope cancel it would cancel all of the jobs within the IO scope that's obviously not a good idea because you could have literally hundreds of jobs running on the background thread on the IO scope or IO context whatever you call it and if you hit cancel it would cancel them all so how do you basically this job sort of pattern is how you get around that so what you want to do is you want to write IO plus the job and then if I ever want to cancel just that one job then I write job cancel and that's the magic so then you don't kind of shut down the entire IO co-routine context you're only going to shut down that one job that you started up so that's that's kind of the focus of this video showing you how to start one job within a context and then only cancel that job and take action if that job is canceled ok so now in here I'm going to do print line and let the user know or let the log know that this is starting up so I'll say co-routine this it's going to refer to you can see that this refers to the co-routine scope so it's going to have a memory address so I'm saying this routine is activated with this job and a write the job in there and now we want to create start our progress so for I'll do I in progress dot dot and then end at progress max so I'm going I'm I'm looping this integer i from the progress start to the progress max if we scroll to the top we see that that goes from 0 to 100 that's all it does so it would be you know 0 1 2 3 all the way up to 100 so then in here I want to delay this to simulate what a request would be and I want to do job underscore time / progress max so what that's going to do is it's going to guarantee and I want to cast this to a long story and that's going to guarantee that this job is only going to take up to the job time which is 4,000 milliseconds so if you want the job to only take 3,000 milliseconds whatever you want change that it's just for demonstration purposes that's all this is going to do and then I want to set the progress bar as this goes along so this dot mentioned the progress bar I'm referring to this the progress bar that this is activated on to and I want to set that progress so progress equals I so now the last thing that we want to do is we want to update the UI and let the user know that this job is complete so you might be tempted to do you know what was it the text job complete text set text and then just say that the job was complete so I could say job is complete but that would create an error because you're trying to access a text view that exists on the main thread from a background thread remember this is still on the i/o thread so we're gonna create another method that takes care of this for us oh we still need to build our reset job method too but let's build this show or sorry this update text view method first so I'm gonna call it fun I could do private I guess private fun update job complete text view it's gonna take text as input which is going to be a string and inside here I want to do kind of the same thing we did with the toast it's going to be global scope don't launch I want to launch on the main thread and inside here I just want to update the text view so I'm going to take this put it here I'm going to cut cut this text do that and then do update job complete text view a new job is going that ensures that no matter what co-routine what context where this is called from it will update that textview on the main thread and i'm gonna do the same thing up here where I updated wherever I did it right here so it says I'm doing job complete text setting the text so update job complete text view and set that to null or empty and I can delete that one by pressing ctrl Y so now the last thing we need to do is go into reset job and write the code required to completely reset our job so if it's running the progress bar needs to get reset the job needs to be canceled all that kind of stuff so let's go in here and the first thing we want to do is write if the job is active so if it if it is currently running or the job is completed so remember there's kind of two situations here if we allow the job to get to completion the job will be marked as a completed status so is completed will return true if the job is currently if the job is currently running but it's not completed it will have an active status so we need to handle both of those scenarios so if the job is active or if the job is completed then we want to cancel the job so I can do job cancel and I can pass a cancellation exception so cancel can sell Asian exception and pass a message so this is I'm just gonna say resetting job and just kind of as an FYI this cancellation exception will actually get caught inside of our invoke on completion so that's the throwable that you'll see right here it's well if we call job cancel this cancellation exception will get caught by this invoke on completion so that's going to be this message that we see this is going to be the message resetting job that's the one that we're going to see print out here so if you need any kind of it see this is this is this is not a I know I'm probably going through this really quickly and you think this is really simple but this is actually a really powerful thing you're you can cancel a job you can pass an exception and then you can take action depending on whatever that exception is and all of this is just so streamlined so easy to do depending on you know your different error messages you might want to show a dialog if it's a bad network connection you might want to show a toast message all kinds of different things and all of this is very easy to do writing custom logic depending on the message and you have even control of what the message is so really cool stuff really powerful stuff so the last thing is after our job is cancelled I want to initialize the job once again and the reason why you need to initialize the job again is because one it has once it has been cancelled you can't reuse that job so if we take a look at the anit job method right here we're an act we're actually initializing a new job and then we're adding an invoke on complete on completion interface here so if a job is canceled just remember this if a job is canceled you can't reuse that job you have to create a new one so that's why I am creating a new job here so now before we run this let's just quickly kind of go through this Oh actually to also scroll to the top here and call a progress bar start or cancel so job progress bar dot start job or cancel and I want to pass that job so for those of you who are unfamiliar with extension functions this is how you use it so I'm declaring a method saying start job or cancel it can only be called on a progress bar that's why I'm saying progress bar dot start job or cancel and then passing that job so anyway let's say let's quickly run through the logic before before I run it just to kind of review everything so when the application starts an onclicklistener is set to the button if this job is not initialized because it's a late and knit variable so basically the first time when the activity is started and the button is clicked we will initialize the job let's take a look at a knit job if I scroll down a knit job the first thing is the start job number one message is attached to that button the textview the completion textview is set to blank the job is initialized so we create a new job we add an invoke on completion interface which handles the event of the job completion or the job cancellation and then it will either it will show a toast message if there was a cancellation and let the user know what's going on so it's a very important thing being able to take action on the job when it's cancelled or completed then after you do that we have just our progress bar being reset so scrolling back up let's take a look what's next so that's initializing the job next we have our start job or cancel so in here if the progress bar is greater than zero so in other words if the job is already active in doing something then we want to cancel that job so job is already active I want to cancel the job which is handled by the reset job method if I scroll down here reset job just checks for if it's active if it's completed and then it will cancel the job and throw that cancellation exception and then initialize a brand new job so if it's canceled this cancellation exception will get caught by our invoke on completion interface so this is the exception get that gets passed here then we can take action and let the user know what what happened with that job so the last kind of part of this if we go back to our start job or cancel method is the else statement so if the progress is not started if there's not currently an active job before you want to change the text to cancel job number one because now the job has started if they click the button it will be canceling it and then we fire up that new KO routine with the job so this is probably the most important thing about this this core team scope ko routine context kind of idea so remember if I didn't pass this job here and I just had the IO IO context passed there and then later on I canceled that co-routine scope it would cancel all the jobs within that scope so that's that is a very bad thing you don't want to do that that's the thing that we're trying to avoid so instead which is a very easy thing to do you just pass your job you do IO plus job so it creates kind of an its own isolated environment just for your job and it fires up the KO routine and starts it up then we have complete control over it right like I said we can mark it as completed we can cancel it we can do whatever and then when it's completed or when it's cancelled our our invoke on completion interface will take care of that and we can take some action so that is it let's run it and take a look and just make sure that there's no errors before I send you on your way because I know that would upset you guys I'm going to click start job there you can see the progress bar starts I'm gonna let this one finish so letting it get all the way to the end should take 4,000 milliseconds it says job is complete everything looks good now I'm going to cancel that job so reset everything it says resetting job there's our invoke on completion interface canceling that or catching that cancellation I'm gonna do job start job number one again and now I'm going to cancel it kind of midway through and then we get that that cancellation message so we're updating the UI we're letting the user know what's going on everything is working as we expect so really kind of cool way to manage background jobs to have a lot of control over them like I said in the past using rxjava async task executor z' all these things required so much more code to do this and it was just a lot harder you know being able to manage a job like this I think is a really great thing and you can have you can have multiple jobs like I could have a whole bunch of different jobs inside of this whatever you know whatever class you were doing this in and you could do co-routine scope io + job 1 + job two plus job 3 whatever you could create all of these different little environments to have these independent jobs running and you have complete control over them so it's a really really powerful way I think to do threading to do asynchronous work and have everything kind of work together and so that's going to be it for this video the last thing I want to talk about is my newest upcoming course on my website powerful Android apps with jetpack architecture Colin mvvm we're actually going to be using mvi architecture navigation components which is the new way to navigate with fragments room co-routines obviously retrofit to dagger to rest api integration all kinds of really really great topics all the newest latest and greatest stuff from jetpack and of course this is going to be showcasing some of the best features about co-routines if any of you familiar with my other courses in particular the one I want to talk about is the local database caching course with the REST API you know that in this course we built a network bound resource class right not Network Status class it's a network bound resource class this one right here this these couple of that manages kind of our our database transactions our room persistence library transactions looking at the cash updating the cash all that kind of stuff inside of that class is where we're going to be adding these jobs and having this cancellation completable functionality and you'll see it really pay off and show some real great dividends for handling error messages handling completions all Network delays all that kind of stuff so I definitely encourage you if you're curious to check out the cashing course or if you only want to know about the newest jetpack stuff hang on and wait for that powerful and reenact powerful Android apps with jetpack architecture course that is going to be it for this video if you want to see more co-routines videos make sure to leave a like and leave a comment and let me know I'm kind of bouncing back and forth between a bunch of topics right now so your input is very valuable I like to do things that most people want to see so that's it for this video thanks for watching and I'll see you in the next one you
Info
Channel: CodingWithMitch
Views: 36,427
Rating: 4.9464989 out of 5
Keywords: kotlin coroutines, coroutines, android coroutines, android kotlin coroutines, android kotlin coroutines tutorial, android kotlin coroutines job, coroutine job, kotlin coroutines job, kotlin coroutines tutorial, kotlin thread, kotlin thread tutorial, kotlin coroutines concurrent, kotlin concurrency, kotlin coroutines example, codingwithmitch kotlin
Id: UsHTxOILP5g
Channel Id: undefined
Length: 32min 35sec (1955 seconds)
Published: Thu Aug 15 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.