Kotlin Coroutine (High-quality Course)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
Hi, this is Sriyank Siddhartha and welcome to my course. In this one single course, I will teach you everything you need to know about Coroutines in Kotlin. This is going to be a 2 hour course. So for simplicity, I have divided this course into 5 different chapters. These chapters are designed in such a way that you will start from building your foundation and end up mastering a particular topic. So in the first chapter you will learn all the basic and foundation of Coroutines in Kotlin. Such as what exactly is a Coroutine? How can you create them? What are Coroutine builders such as launch, async and runBlocking functions. What are suspending functions? And, How coroutines are different from threads? Fine. Once you build your foundation. We will move on to next chapter i.e. Chapter 2. In this chapter, we will dive into various Coroutine Builders. The basics of which we already covered in the previous chapter. So in this chapter we will dive a little deeper into each coroutine builder. And in the same chapter we will write our first test case using coroutine. Next, we have Chatper 3. So in this chapter we will start to see Intermediate level concepts. So once we have build our foundation we will raise our level. So this chapter is basically based on Coroutine cancellation and also exception handling. Then we will move on to chapter number 4 where we will continue to see the intermediate level concepts. So in this chapter we will learn how to compose suspending functions such as how to execute them sequentially, how to execute them concurrently, or even lazily. After this chapter comes the last and final chapter i.e. chapter 5, where we will increase our level from intermediate to little advanced concepts of coroutines. So in this chapter we will learn the core concepts of Coroutines such as CoroutineScope, CoroutineContext, and Dispatchers. Now, these three topics are very very crucial if you want to use Coroutines in your application and at times they might be very very confusing while using them in your app. So this final chapter will give you more insight into the world of Coroutine. So make sure you don't skip this chapter. Now, to make things clear and precise in this course, each topic is explained by using beutiful slides and of course also explained using appropriate demos. So make sure you follow each demo step by step along with me so that you can make the most out of this course. And for your convenience, each demo source code has been uploaded to Github. So you can reference them anytime you want to. And of course, before we start this video if you are new please subscribe to my channel and give this video a thumbs up. This is Sriyank Siddhartha and let's start this course. So let's start with our first chapter and understand the basics of Coroutine and what exactly is a Coroutine in Kotlin and how can you use it your app. So firstly, what are coroutines? And what is it used for? Well, to understand what are coroutines, you would need to first understand, how exactly your application works when the user launches your application. So when the user launches the application, a default THREAD is created, and this thread is known as MAIN THREAD. Now, this main thread is the life of the application. Let us represent the main thread with the help of this blue arrow. And on this main thread, we perform very small and lightweight operations: Such as UI interactions, click of the button, mathematical operations, or lightweight logical operations. So in short, we use the main thread to compute small operations. Now, what about the long and heavy operations. Such as that requires the use of internet or uploads or download of a file or loading and displaying an image from the server or running some heavy database queries. Well, if you run these heavy operations on the same main thread. Then in that case your MAIN THREAD will be blocked. And when your main thread gets blocked then your application will freeze. In simple words, it will get hanged. And in case, if your main thread remains blocked for a longer time such as 5 seconds or something then eventually your application will shut down . with a crash message. And I am sure while using an app you must have experienced such things. Where your phone becomes slow and your app crashes. Right? So running such heavy operations on the main thread is indeed. a bad idea. To counter this, we have a solution. Instead of using the main thread, we can create a worker thread or the background thread. And on this worker thread . which is also known as background thread we can run heavy operations. Such as we can create a thread. to perform some network operations. We can create another background thread, to download or upload a file. Similarly, we can launch more threads to load images or to perform some heavy database queries. So in general, you always create a new thread to perform some operations . without affecting your main thread. Sounds like a solution right? But there is a limit of how many background threads you can create at a time. Because creating threads is very very expensive. And if you create more and more threads, then there would be a time when your device will run out of memory. And eventually. once again your app will shut down. Hence, creating so many background threads is also not a good solution. It's a bad idea. So here come coroutines into the picture. So say hello to coroutines. When you use coroutines then you don't have to create so many threads for each operation. Instead You can have just one background thread And on this thread, you can launch coroutines. Such as launch a coroutine to perform File Upload Launch another coroutine on the same background thread . to perform some network operations. Launch one more coroutine to download a file. Similarly, we can have more coroutines to perform other operations. like this. In short, with the memory consumption of one background thread, you can perform so many heavy operations. How cool is that? So this is what coroutine does. Nice and Simple. So now, how do we define a coroutine? Well, you can think of coroutine as light-weight threads. Like threads, coroutines can run in parallel, wait for each other to finish, and even communicate with each other. But remember coroutines are not threads. So please note this. This is very important. The biggest difference, when compared to a thread, is that coroutines are very very cheap, They are almost free: we can create thousands of them, and we don't have to worry about memory consumption. So for modern applications, coroutines are indeed the modern solution. Don't you think this is awesome well of course it is. That's why coroutines are trending today. And that's why you are here to learn about it. So now how to use coroutines? Well, for that we would need a Kotlin project right? So let's create a new project in IntelliJ IDE. Click on New Project. From here, select Gradle. Because of coroutines, you would need to integrate it to your project using either Gradle or maven. So I will use Gradle at the moment. At the topic, it will show the system's default installed JDK. Right? Then select, Kotlin/JVM. make sure only this is selected. Next. Give project name as KotlinCoroutines Then click Finish. While creating a new project, make sure you have an active internet connection. Otherwise, it won't work. And creating a new project might take a little time. So have patience. Once your project is created. Now, this main function actually operates on the main thread which we just saw in our slide. Right? And if you write some code within this main function. Such as print statements. Then these two print statements will also execute in the main thread. Because they are being called from the scope of the main function, which is running on the main thread right? To prove my point, I am going to print the thread name. Let us run the program. So here we go we are indeed using the main thread. Perfect. Now, let us create a background thread which is also known as a worker thread. So this lambda expression is going to create a new thread for us. And within this thread, let us perform something. Let's add a print statement first. And also we will verify on which thread this code will be executed. Let's pretend to do some work. This will do some work for 1000 milli-seconds. i.e. 1 second. Well, in real projects, you would need to replace this statement (Thread.sleep) by some real task. right so don't use this statement in real projects. Then end the thread with another print statement. I hope this code makes sense to you now. Let's run the program. So here our main program started in the main thread and ended in the main thread. Which you can see in the output. And the code that belonged to the thread, executed in some other thread which is actually the background thread. Fine? So how exactly our program was executed. Firstly from the output, you can observe that these two code were executed independently of each other. They both started and ended in their own way. So this statement (print statement) first produce this output. And then in sequence, when this thread lambda expression was executed, then it launches a new thread in the background to do these works. Right? So this background thread did not block the code of the main thread. Which also means, now these two threads are running in parallel. Hence, immediately after this statement was executed, the code within the main thread resumes. This statement will not wait for this background thread to finish its work. Because they will run in parallel. So immediately after main program starts, you get the main program ends in the output console. And now the background thread was running in parallel. right hence the code here within the thread once starts to execute. produces output accordingly. Such as Fake work starts and finishes. So what I want to say is that the code in the background thread did not block the code of the main thread. They ran in parallel i.e. in a concurrent manner. Quite simple isn't it? And also, if you run the program. then you will find a gap of one second between these two statements. It is due to our fake work going on at this line of code. Fine? Now moving on, here I want you to note one more thing. Even after the last statement in the main function was executed, then also, the application waited for our background thread to execute and complete. And only after these three statements were executed, our application ended. Which you can find here. So just note that in case of threads, the application waits for all the background threads to complete. Right? Please note this, I will come back to this shortly when we will discuss coroutines. Now let us replace this thread { } by a coroutine because our ultimate objective is to use coroutine instead of threads right? So here to create a coroutine you can use GlobalScope.launch function. Once you select it, you will find a new import. because the coroutines belong to this package. Fine? So this launch function what it does, And we can check on which background thread the coroutine is operating using this function. Fine? And here we are again pretending to some fake work. and after the work completes, we print fake work finished. Let’s run the app. So here our main program started and ended. and our app also finished with exit code 0. But there are no signs of the output which belongs to this code over here (coroutine code). So what's wrong with our program? Well, just now I showed you that, in case of a thread, the main function waits for the background threads to finish their work. But in the case of a coroutine, things are a bit different. When a coroutine is launched it gets attached to a background thread of course but the application by default do not know it has to wait for the coroutine code to end. So this is another difference between while using thread and while using coroutine. So what is the solution to this? How can we make the main function to wait for the coroutine? Well, for this we need to manually make our application, wait for the coroutine to finish its job. So here let's add since our fake work is taking 1 second to finish, here I am using 2 seconds. which will ensure the main function ends only after the coroutine ends. Right? Run the application. So here we go, our program worked perfectly fine this time. Also, for these two print statements, you will find we are not operating on the main thread. The name of the thread is something which belongs to the background. So this is how we create a coroutine, do some dummy work and make our main function to wait for the dummy work to finish. Fine? Now you might ask, suppose if our real job is to upload a file to the server, then in such a case practically it is impossible to know how much time it will take to upload the file. In short, we won't know, what time we need to fill here so that we can wait for the coroutine to end. right? So in real projects, what exactly we need to write in place of this code. Well, for that you need to wait a little bit. Right now I just wanted to show you how to write your first program using coroutine. So wait a little bit, follow my coroutine videos and you will definitely get your answer at right time. That’s my promise. Perfect. So right now, let's get a quick summary of what we saw just now. So we create a thread using this lambda expression in kotlin. And we delayed the thread or pretended that we are doing something by using this Thread.sleep function. And we saw, we create a coroutine which is attached to a thread by using this syntax. But we used the same Thread.sleep function within the coroutine. Right? Now, this Thread.sleep basically blocks the entire thread. So if some other coroutines are operating within the same thread as this coroutine is operating, then it will basically block that other coroutine as well. Which is not good right? So what is the solution to this? Well, coroutine provides a solution to this. Instead of this (Thread.sleep) you can use delay function. So this delay, when executed, does not block the thread on which it is operating. Let me elaborate a bit more and show you how the delay is more efficient that Thread.sleep function. So here when this code is executed a thread is created. But when Thread.sleep function is executed, then for one second, your thread. will be completely blocked. Meaning, for this time frame, your thread won’t be able to do other tasks. It gets busy. Right? Now, let us come to our coroutine code. So when this code is executed,. it creates a coroutine that is attached to a thread. For clarity, let's name the coroutine as C1. And of course, there could be other coroutines that are operating some other task on this same thread. I guess no doubt till now. Now when this statement delay(1000) is executed, then it basically suspends the coroutine for 1 complete second. But it does not block the thread at all. Which means the execution of other coroutines are not at all affected. They keep operating in the usual manner. So I hope this clearly shows you the differences between delay function and Thread.sleep function. So here in our program, let us replace this statement (Thread.sleep) by delay function. Now, here I want to talk a little bit more about this delay function. Let us start from the beginning. Now when we launch a coroutine, then let us assume our coroutine starts on Thread name T1. So the next statement which will be executed, will of course, execute on Thread T1. Right? But when the delay is executed, then it basically suspends the coroutine or pauses the coroutine. And in that case the thread becomes free. Meaning the thread T1 is firstly not blocked and it can associate with other coroutines to perform other tasks. Right? So far so good. But after delaying for 1 second, when this print statement executes, then what do you think, on which thread this statement will be executed? Well, here is the twist. It is not necessary that this statement will be executed in the same thread T1. It couldd. be Thread T1 or it could be some other thread maybe T2 or T3. So in short, throughout the lifetime of a coroutine, the thread might change but don’t worry it does not impact the performance of your application. So please note this. Let us run the program. So here, you can see it is a coincidence that this Fake work finished statement was executed in the same thread as it was executed for this statement. It doesn't mean this thread will be always same. It can definitely change if we run the program in future. Fine? Now moving on, at the bottom we have another Thread.sleep function. Let's replace it by delay function. As soon as you do it? the compiler is not happy. It says you cannot call the suspending function from outside a coroutine. Let's check the definition of this delay function. Here we have a modifier 'suspend'. This creates more questions for us. What is a suspend modifier? And what is a suspending function? Well, a function with a 'suspend' modifier is basically known as suspending function. The suspending functions are only allowed to be called from a coroutine or from another suspending function. In short, they cannot be called from outside a coroutine. So this is the reason why the compiler was complaining us. So please remember these three points. These are very basic but very important things to remember while dealing with coroutines. So now we know that this delay is a suspending function. Which means, we cannot call delay function like this, outside the coroutine. So what is the solution to this, well the solution is to wrap the delay function within runBlocking lambda expression Like this. Run the program. Here we go. the output remains the same. So this runBlocking function, what it does. It basically creates a new coroutine but this time the coroutine blocks the current thread which is main thread in our case. And then calling delay will wait for our previous coroutine to finish its task. So what we were able to achieve using Thread.sleep function, we are achieving that now by using these two lines of code. But again, this is still not exactly the right way to wait for other coroutines to finish work. Well, what is the right way to wait for other coroutines to finish, we will check it little later. Not right now. For now, just focus on the concepts that I am teaching. Also, for now, please note that these two functions create a new coroutine right? But. they are completely different. This launch function creates a coroutine that does not block the main thread. But this runBlocking creates a coroutine that blocks the main thread. So right now, just remember this small difference. We will discuss more about them later. Now moving on, you can present the entire code in a little different way. Suppose if you wrap this entire main function within runBlocking lambda expression. And remove the runBlocking from here. And run the program, then the output remains the same. If you analyze the code in sequence, then this main function starts to execute in MAIN thread. Then using runBlocking we launch a new coroutine that blocks the main thread, meaning this coroutine runs on the main thread. Right? Then this print statement runs on the main thread. because this print statement lies within the scope of runBlocking method. Please note that. But when this launch function is executed, it creates a child coroutine but in a background thread. Meaning this entire code starts executing parallelly in a concurrent manner in the background. Let us assume the thread is T1. And then I have already explained to you how these codes will be executed. So I guess no need to discuss again. Then this delay 2000 function is actually present within the scope of runBlocking function. So this will execute in the main thread and hence it will block the main thread and wait for our launch coroutine to finish. Just like it was doing previously. Right? And then this print statement executes in the main thread. So I hope things are clear now. Now, while dealing with coroutines it is very very important for you to keep track of the threads that are being used. So that is why right from the beginning of this video, I am emphasising on the thread being used at each and every line of code. And trust me if you are clear with the basics then this topic of coroutine will become very very easy for you. Perfect. You can further write the same code in a more optimised way. You can make this main function as expression. The kotlin way of writing code. Like this. Don't worry the output remains the same. Perfect? Now let's come back to the suspending function. We actually got deviated from this topic to explore runBlocking. So, you can also create your own suspending functions as well. Use the suspend modifier. Give function name and define parameters. Let's add a delay function. And then you can replace delay with mySuspendFunc call. Like this. And the output, of course, remains the same. Fine? You can run the program and verify the result yourself. If you are feeling jumbled at this point. then let us summarise what we have covered so far in this video? we now know what are coroutines. and how they are different from threads. We then learnt how to set up a Kotlin project and add coroutine dependency by using Gradle. Then we saw what are suspending functions and how to create such functions on our own. We also saw two ways to create coroutines. First by using launch function. and another by using runBlocking function. We also explored the basic differences between them. I hope you remember that. And above all, we always explored on which thread your coroutine is operating. Well, remember if you are able to keep track of threads while using coroutine then you can very very easily write complex code using coroutine in your application. And in case if you have any confusion regarding threads while using coroutine then you must watch this video once again. There is no harm in that. And if you are curious to know what is the exact way to wait for the coroutine to finish. Or if you want to know more about runBlocking function and its right usage then you must watch chapter 2 of this course. So congratulations on completing the first chapter. I am sure you enjoyed it. So without wasting any time let's jump on to our next chapter i.e. chapter number 2. So again this is Sriyank Siddhartha and I welcome you all to the next chapter of this course. In this chapter you will learn in detail about coroutine coroutine builders in kotlin. Now coroutine builders are basically a few functions such as launch and runBlocking functions. And from the previous video we have already got a basic idea about them. So in this video we will dive deeper and explore them in detail. Great so now, what exactly are Coroutine Builders? Well, as the name implies, coroutine builders are nothing but the functions using which we create a coroutine. As simple as that. So what are different types of coroutine builders? Well, the first is the most commonly used one. i.e. the launch function. The second is the async function and the third is the runBlocking function. Now apart from these three, there are other ways to create a coroutine but these are the most important ones. So please note this. Now, in case of launch function, we also have something called, GlobalScope.launch. This GlobalScope is basically a companion object. And in the previous video we created our first coroutine using this syntax. Now don't worry we will shortly discuss what is the difference between this GlobalScope.launch and only the launch function. Similarly, for async as well, we have GlobalScope.async function. But for runBlocking we don't have anything like that. We just have simple plain runBlocking function. Fine? So let us first get some clarity on what is the significance of using GlobalScope companion object? Well, let us assume we launch an application. So this entire red box represents the lifetime of the application, let us assume that. Now, in your application, suppose you are currently in a Login screen. And from this screen you launch a coroutine C1 using the launch function. And then you navigate to another screen, maybe a home screen or something. And here as well you launch another coroutine C2 using the launch function. Now so far so good. But . when you try to close this screen and navigate back to the previous screen. Then what happens is that, this Home Screen gets destroyed . and along with this screen the Coroutine C2 is also destroyed. Now, the question arises why the coroutine C2 was destroyed? Well, this launch function creates a coroutine in the local scope. So when the scope of Home Screen is destroyed, then the child coroutine such as C2 is also destroyed. In short, the lifespan of this coroutine exist within the lifespan of its local scope. Fine? Similarly, when the scope of this Login screen will get destroyed, then ultimately this coroutine C1 will also get destroyed. Like this. Perfect. Now what about, if we create a coroutine using GlobalScope.launch function. Well, using this syntax, we actually create a coroutine at Global level or at the application level. So the global coroutines are the top-level coroutines and it can survive the entire lifespan of the application. So even if all the local scopes are destroyed, then also the global coroutine, no matter from which local scope it was launched,. it can survive the entire life span of the application. Fine? So please note this. Now, the question arises, when should you launch coroutine Globally and when should you launch a coroutine locally? Well, it is a subjective question and would require separate discussion on that. But for now I will show you a big picture. You can use GlobalScope, in cases where you don't depend on the local scopes. Such as once you click on a button to download a file, then it can run in the global scope and let it complete in the background. Because generally the downloaded file is not needed during your ongoing activities. You just start the download operation and move on with your other work. Right? The same is the case of playing the music. Just start playing the music and it has nothing to do with your other ongoing task. Fine? Now moving forward, for the launch function. You can use it where you want to compute some values within a local scope and end it there only. Or you can do some login, and you need to end that login operation right there, then you can simply use the launch function. So I hope it make sense now. Movin on . at the end, also note that using GlobalScope.launch is highly discouraged. Because if you create a coroutine globally and you forget about it, then it will keep on running in the background and consume a lot of memory right? Which is not good actually. So you need to use it very very carefully. In short, using launch function should be your default choice. So please note this. Great. Now, similar to the case of launch function, in case of async function as well, we can use GlobalScope companion object to launch the coroutine globally. The jist of the difference between these two remains the same. But this does not mean that launch and async are the same. Well, they are different. And this is what we are going to discuss in this video. How these three coroutine builders are different from each other. So let us start with the launch function. So here this is the same program, that we wrote in the previous video. Here we start our main program. Then we create a Global coroutine, that runs on a global thread in the background. Here are the coroutine operations. Then we wait for the coroutine to finish. And since this is a suspending function which we cannot use directly inside the main function. So that is why we used runBlocking over here. Fine? I hope you remember this. And finally our main program ends. If you run the program, we get this output. I guess nothing new until now. But please note the name of the thread on which our coroutine is running. I will come back to it shortly. Now, as mentioned just now, you should not use GlobalScope companion object, unless required. Right now we are performing a very simple operation within a coroutine. So we don't need to run it in the global scope. right? So let's remove GlobalScope from here. And run the program. So here we go, we have some twist. The coroutine is now running in the main thread. Interesting, isn't it? Let us update the comments first. Now the question arises, why on this holy earth, our coroutine ran on the main thread. Well, this is because this launch coroutine builder is actually present within the scope of the parent runBlocking coroutine builder. And since this runBlocking runs on the main thread, so this child coroutine inherits the scope of parent coroutine and hence runs on the main thread. Fine? Well, this is the property of the launch coroutine builder which you need to remember. So in short, if this runBlocking creates a coroutine that runs on Thread T1, then this child coroutine will also run on thread T1. So I hope this is clear now. Next, within this coroutine, the first statement will of course run on the main thread. But when this suspending function delay is executed, then our coroutine suspends right? Which means, the next statement which will be executed, will either execute on the main thread or some other thread. Well, it depends on the situation. So I guess you are getting a clearer picture now. Now moving ahead, let us explore more. Let us see the definition of this launch function. Well, this launch function returns a Job object. So let us see what this job object does. let us get the job object Now using this job object you can control this coroutine. Let me show you how. As mentioned earlier, the usage of delay over here is not the right way to wait for the coroutine to finish right? So instead of this statement You can use job.join() So this join function will wait for the coroutine to finish its execution. Only after which the next statement will be executed. Let us now run the applicaition and see what happens. So here we go, our program worked perfectly fine. So now you can remove this statement. Perfect. Also, please note that, using this job object you can even cancel this coroutine. Well, how to cancel a coroutine? For that you need to wait for my next video. Cancellation requires a detailed explaination. So let us summarize the launch coroutine builder. So when this function is executed, then it creates a coroutine that operates on a thread. And of course, on this same thread, there could be other coroutines that can operate at the same time. And when this delay function is executed, then it basically suspends the coroutine. But remember the thread remains free for this time period. And other coroutine can still continue to operate on this thread. Only the coroutine is blocked for this time period. Fine? And this launch function returns a job object. Right? So using this job object, you can wait for the coroutine to finish or even cancel the coroutine, which we will explore later. So this launch builder creates a coroutine that runs without blocking the current thread. Always remember this, it does not block the thread on which it operates. And remember, it inherits the thread and the coroutine scope of the immediate parent coroutine. Which we saw in our demo. Next, it returns the Job object. And using this object you can cancel the coroutine or wait for the coroutine to finish. Basically this job object allows you to control the coroutine. Fine? Nice and simple. So this was all about the launch coroutine builder. Now moving on, It is now time to explore async coroutine builder. Well, it is very similar to the launch coroutine builder. But with a little difference. So let us explore that. So here in place of launch, just replace it by async. And that is it. You have created a coroutine using async function. And similar to launch function, this async will inherit the coroutine scope from the immediate parent coroutine. which is runBlocking in our case. Run the program. So the output remains the same. But there is a difference while using async function. Well, this function does not exactly returns the Job object. It returns an object of the type Deferred And this deferred is of the generic type. So right now we are not returning anything from this coroutine. So we can put Unit here. But from this lambda expression, if you return a String value. such as Sriyank Siddhartha Then instead of Unit you need to use String. If you return an integer, such as 20 Then here, you can use Integer generic type. Great. Isn't it? Now, if you don't want to use this 15 in your code, then calling join function on this deferredJob object will just wait for the coroutine to finish. But if you want to use this value, then instead of join you can use await function. So this await is like a promise. It will wait for the coroutine to finish and after it finish, you will get your desired value. So on the left, you get the integer value. Fine? And then you can use the value in your program. As simple as that. And remember, just like delay, the await function, and join function are also suspending functions. So it requires to execute within a coroutine scope. Fine? So please note this. Now, moving on, if you use GlobalScope here. Then your coroutine will run globally. If you run the program, then the output remains same, but only now our coroutine is being executed in the global scope. i.e. at the application level. Fine? But it's not required now. So let's remove it. Now, at the end, let's see the signature of this Deferred class. Well, this class is actually the subclass of the Job. So that is why we were also able to call the join function on the deferredJob object. So please note this. Perfect! So let us summarise the async function. Well, just like launch coroutine builder, the basic properties of the async function and the way it operates remains the same. For example, how calling the delay function, just suspends the coroutine. It remains the same. But using async function, you can return some data. And you can retrieve data using the await function. And of course, you can call the join function or the cancel function as per your need. So in short, the await function just like launch function creates a coroutine without blocking the current thread. And it inherits the thread and the scope from its immediate parent coroutine. Fine? Next, this function returns the Deferred object which can carry your desired result. And finally using that deferred object, you can cancel the coroutine, or wait for coroutine to finish, or even retrieve the returned result. How cool is that? Moving ahead, Let us see runBlocking coroutine builder. What is it used for? Well, practically we don't use runBlocking coroutine in the way we have used it in our program. We have used it over here, so that we can run suspending functions like await or join over here. You can think of it like. I am using it runBlocking just to explain you how coroutine works. But this is not the right purpose of using runBlocking. Now the question arises, what is the practical use of runBlocking function. Well, this runBlocking is generally used to write test cases to test suspending functions. For example, suppose we have a suspending function over here which you want to test. So to test a function, you would need to write test cases. Let us do that. Let's create a new Kotlin class. Let's call it SimpleTest Here let's use @Test annotation and define a function. Now, you do you test something. We test something by asserting something. Such as Assest.assertEquals method. this method will check if this 10 is equal to 5 + 5 or not? Let us run the test. Great, our test passed. Now, let us test this myOwnSuspendingFunc. So if you try calling myOwnSuspendingFunc from here, then the compiler won't allow you to do that. It will say, you cannot call a suspending function from within a normal function. And as per the rule which we saw in the previous video, we can only call suspending function either from a coroutine or from within another suspending function. right? I hope you remember that. So what I will do that, I will wrap this function within runBlocking coroutine. Like this. So now the error is gone. Run the test case. Great, our test passed. So this is the actual purpose of using runBlocking coroutine. And of course, later on, I will definitely show you what are the other use cased of runBlocking coroutine. Fine? Now in the end, please note that, this launch and async coroutine builders never block the thread in which it operates. But this runBlocking always block the thread in which it operates. This non-blocking and the blocking nature of these coroutines are very important for you to remember. Nice and simple! So finally let us summarise this video. Well, in this video we explored what are coroutine builders such as launch, async, and runBlocking. Remember launch and async are non-blocking in nature but runBlocking is a blocking coroutine which blocks the thread. We explored the differences between launch and async coroutine builders. Then we explored what is GlobalScope companion object and why you should not use it? Also we saw, the usage of Deferred object and it is actually a subclass of the Job interface. Fine? And also, we explored how to use await(), join(), and cancel() functions. Hey but wait, we did not explore anything much about this cancel function because cancelling a coroutine is a huge topic of discussion. So for that you must watch next chapter of this course. So congratulations on completing the 2nd chapter. So without wasting anytime let's jump on to our next chapter. So again this is Sriyank Siddhartha and I welcome you all to the next chapter of this course. In this chapter you will learn about coroutines in terms of Cancellation, timeouts and how to handle cancellation exception in a coroutine. So let's get started. Now the first question that comes to my mind is, why would you cancel a coroutine? Why can't we just let it finish its work, for which it was meant to be? Well, there are several reasons for which you would need to cancel the coroutine. There might be a case where you no longer need the result from the coroutine, in that case, you can cancel the coroutine. Or if the coroutine is taking too long to perform a task, then you can cancel that coroutine and find another way to execute the same task. In short, the reason for cancellation could be anything. So let's explore how to cancel a coroutine. Now to cancel a coroutine, the coroutine has to be cooperative. So what does this mean? Well, I am going to keep the suspense on what does cooperative mean exactly, for the next few minutes. So right now don't worry about what this cooperative means. When the time comes, I will reveal what it means. So right now just remember, to cancel a coroutine, it has to be cooperative. Fine? Now, let's take a look at the sample code. Here we have a coroutine. And the code within your coroutine has to be cooperative in order to get cancelled. Please note this. Now, to cancel the coroutine we need to call cancel() function on the job object. So if your coroutine is cooperative then it will get cancelled. But if your coroutine is not cooperative, then it will not get cancelled and it will continue to operate in the usual manner. And when your coroutine fails to cancel then this join function will wait for the coroutine to finish. In short, this join function will be effective only when this cancel function fails to cancel the coroutine. So again please note this. This is very important. So basically, this cancel function and join function are used in conjunction. They are used so often that, we have a separate function that combines the property of these two functions. So in place of them, we can use cancelAndJoin function. When this function is called, then if the coroutine is cooperative it will cancel the coroutine. Else if the coroutine is not cooperative then it will wait for the coroutine to finish. Fine? So I hope it make sense now. Now, it is time to unveil the biggest mystery of this video. What exactly we mean by cooperative? What makes a coroutine cooperative? Well, there are basically two ways to make a coroutine cooperative. Now, the first way is to periodically invoke a suspending function that checks for cancellation. And only those suspending functions which belong to kotlinx.coroutines package will make your coroutine cooperative and therefore cancellable. For example, the functions like delay, yield etc are the suspending functions which belong to that package. And if you use these functions in your coroutine, then your coroutine will become cooperative and therefore it can be cancelled by calling the cancel function. So let us practically see how to make our coroutine cooperative so that you can co-relate things altogether. So here we have a very very simple program using coroutine. Here we are applying runBlocking coroutine scope, then our program starts we create a non-blocking coroutine that contains a for loop. This loop prints values from 0 to 500. Then we wait for coroutine to finish. Finally, our program ends. If you run the program, It will print values from 0 to 500 And then our program ends. Great. Now, let us put some delay while printing values. Let us use Thread.sleep for 50 milliseconds, over here. Well, I am using Thread.sleep instead of delay function intentionally, just to show you something. Let us run our program. So now our program print values at an interval of 50 milliseconds. So altogether it takes 10 seconds to complete. Right? But I think as a user 10 seconds is way too much. So, in that case, I would like to cancel the coroutine. So here just before join function I will cancel the coroutine. But since our coroutine is going to get launched in the background thread, hence it could immediately get cancelled. So let us use a delay of 100 over here so that we basically print a few values before our coroutine gets cancelled. Let us run our program. So here our program is running, but there are no signs of cancellation. Our program is running throughout for 10 complete seconds. Which means our coroutine did not get cancelled. Right? Now the question arises why? Well, the reason is, at this point of time, our coroutine is not cooperative. Because in our coroutine we are not using any function that belongs to this package. Right? So right now, in our coroutine, we are using a print function and Thread.sleep function, and these two functions don't belong to this coroutines package. So that's the reason why this cancel function did not cancel our coroutine. and hence, this join function came into action and we had to wait for 10 complete seconds so that our coroutine gets finished. So if we use delay instead of this function. Then now, our coroutine becomes cooperative, i.e. it can get cancelled on calling this cancel function. Let us run the program. So here we go, we print a few values and our coroutine got cancelled. Nice and simple. Now, instead of using the cancel and join in two lines, we can use, job.cancelAndJoin() function. Run the program the output remains the same. Great. Now, apart from delay function we also have other functions like yield function. So in case, you don't want your coroutine to delay then yield is the best choice for that. Let me show you how to use it. So here you can use yield instead of delay. And of course, you can use any other suspending functions as per your need. Well, this yield function is cancellable in nature and it does not delay the coroutine as well. Right? So basically this delay 200 won't be of any use over here. Because using this yield will make our coroutine much much faster than it was using delay function. So delaying for 200 is going to print all the values. So let's reduce the time to 10 milliseconds. Let us run the program. Fantastic. Even we delayed for so less time, then also we were able to print values till 43. So yield is one of the best choices to make your coroutine cooperative. Fine? So please note this. Now moving on, let us check the second way to make coroutine cooperative. Well, there is boolean property of isActive, which can be used to check for cancellation status of the coroutine. So when the coroutine is active, then this flag is true but when the coroutine is cancelled, then this flag becomes false. So using this false value of this flag, we can terminate the coroutine internally. Now, in case of Threads, we did not have any such flags. So we are glad that in case of a coroutine, we have got a provision for terminating a coroutine based on a boolean flag. So this is another advantage of using coroutine in place of threads. Again, please note this. So let's go ahead and see the code in action. So firstly let us remove this yield function. The next step would be to check the boolean flag. So right here we can check if the flag is false then let's break out of the loop, and if the loop terminates then eventually our coroutine will finish. Right? And also, within our launch function, we need to pass a Dispatcher. Such as Dispatchers.Default. Now this Dispatchers is something we have not explored yet. But we will explore it shortly. Don't worry. So let us run the program. Well, here we are getting all the values from 0 to 500. This is because our coroutine is getting executed very very quickly before it is getting cancelled. So what we can do is, let's put some delay here. Well, I am using Thread.sleep because if we use delay then it will be like we are using the first way of cancelling the coroutine. And right now we want to see if this isActive flag works or not. So don't use this Thread.sleep function in real projects fine? So let's run our program. So here we go, our coroutine executed for a few milliseconds and then as soon as this cancel function was executed, the isActive flag became false and hence we break out of the loop, which eventually finishes our coroutine. So this is how we use the isActive flag to make coroutine cooperative. Fine? Now, instead of this break, you can also use return@launch So when the coroutine is cancelled, then we return from this launch coroutine level. Right? Which basically terminates the coroutine. This statement is nothing but just a simple kotlin programming concept. Run the program. Great. We get the same output. How cool is that? So in this way by using the isActive flag, and by checking it at a regular interval in each iteration, we can make our coroutine cooperative and hence cancellable. Nice and Simple! Now that we know two different ways to make our coroutine cooperative, let us now move ahead with the next section of this video and explore how to handle CancellationException while cancelling the coroutine. Well, this is yet another important topic related to coroutine cancellation. So let's explore it as well. Now , when you cancel a coroutine by using suspending functions within it, then CancellationException is thrown by your coroutine. Which you can handle and perform some other operations. In short, all the cancellable suspending functions such as yield, delay throw CancellationException when the coroutine is cancelled. Please note this. So here let me modify the program, and use the same program which we saw using the yield function or the delay function. So when you cancel the coroutine, then this yield which is a suspending function throws a CancellationException. So we can wrap the for loop within a try-catch block. Like this. And within the catch block, you can write your code. Great. And just like any other try-catch, you can also add a finallly block. If you run the program, we get something like this. The output from the catch block and from finally block once the coroutine is cancelled. Perfect. Now instead of this yield function, if we put delay function or any other suspending functions that belong to kotlinx.coroutines package, then also the CancellationException will be thrown. Fine? So please note this. Next, you cannot execute a suspending function from the finally block. Because the coroutine running that code is already cancelled. Right? And in the extreme case, if you really want to execute a suspending function from the finally block, then you can wrap that code within withContext(NonCancellable) function. Let's see the same in the demo. So here in finally block, let us put delay(1000) over here. Then you will find we catch the exception, but finally block was not executed, because at this statement another exception was thrown. Well, generally we don't require to use such suspending functions within the finally block. But in the rare case if you need to use such functions then you can wrap the code within withContext() function. And pass NonCancellable companion object as a parameter. Well, this withContext just like launch creates another coroutine, in a new background thread. Fine? So basically this withContext is another coroutine builder. Let us run the program. Here we go, we are able to execute the code within finally block successfully. Great isn't it? Moving on, you can also print your own cancellation message by using job.cancel function. And as a parameter, you can pass the CancellationException instance and pass your message within the constructor. So here let us first split this function into and then pass CancellationException() instance and within this constructor pass your message. Like this. And within the catch block, you can print that message, by using ex which is the variable over here. Dot message. Great. Run the program. So here we go, we got my own crash message. How cool is that? So in this way, we handle CancellationException in a coroutine. Perfect. Now that we know how to handle exceptions. Let us move on to the next section of this video i.e. Timeouts. Well, suppose you launch a coroutine that is taking more time than expected to finish its work. Then, in that case, you can cancel your coroutine. And for time-bounded task, kotlin provides us with special functions. Such as we have withTimeout function and also, we have withTimeoutOrNull function. Well, these two are basically coroutine builders. i.e. just like launch and async functions, they also create coroutines. So let us see how to use them in our program. So let me clean up the entire code. and then let us use withTimeout function. Well, this function is just like launch and async. It will create a new coroutine for us. But if we put 2000 over here. Then if the task within coroutine does not get over within this time frame, then an exception will be thrown. So let us use a for loop. And let us run the program. So after 2 seconds, we got TimeoutCancellationException. Great isn't it? So just like we handle the exception, we can handle exception here as well by using try, catch, and finally. And accordingly, you can put your code here. and here. Now this TimeoutCancellationException is basically the subclass of CancellationException. So please note this. This is something important and you must remember this. Now, next, we have withTimeoutOrNull. So if we use withTimeoutOrNull over here, then the functionality remains the same. i.e. this function is also a coroutine builder. It is going to create a new coroutine for us. But this function is not going to throw any exception. So we can remove this try, catch, and finally blocks. And this function basically returns a value at the end. So if we use "I am done" at the end. Then we get the result over here. And if we use an Integer over here, then we need to change this String to Int data type. Right? Now, in case of a timeout, this function is going to return NULL. So let us use a print statement over here and see what we get. So here we go. After the timeout, we got NULL as lambda result. And remember if there was no timeout, then this result variable will get this valid string object. Fine? Also, please note that this data type should of nullable type. So that it can store a null object. Fine? So this was all about timeouts in case of coroutines. So yes finally we have reached the end of this video. This was a pretty long video. So let us get a big picture of what we learnt so far in this video. So initially we learnt what makes a coroutine cooperative (cancellable)? Then we explored two ways to make coroutine cancellable. First, by using a suspending function within the coroutine such as delay or yield. Then second by using isActive boolean flag. Then we explored how to handle CancellationException while cancelling a coroutine by using try, catch, and finally blocks. Along with this, we saw how to use withContext function to execute a suspending function within the finally block. Then we explored Timeouts. And for that, we explored withTimeout function as well as withTimeoutOrNull function. And in withTimeout function we also saw how to handle TimeoutCancellationException which is basically a subclass of CancellationException. So yes that is it for this chapter. I hope this chapter has expanded your horizon to understand Coroutines better. So let's move on to the next chapter. So again this is Sriyank Siddhartha and welcome to the next chapter of this course i.e. chapter 4. In this chapter we will see various approaches to compose and execute suspending functions. Such as we will explore the sequential, concurrent, and lazy execution of the code within a coroutine. And trust me having a thorough knowledge of this will really help you to use coroutines in your application. Now before you start with this video, there are a few things that you should already know. The first is, you should know the basics of the coroutine. Such as what is a coroutine and how to create a coroutine along with this you should also know what are suspending functions. Next is, you should be familiar with coroutine builders such as launch, async, and runBlocking functions. So let's now see what we are going to cover in this video. We'll first see how functions execution within a coroutine is sequential by default. Then we will find a workaround to make them concurrent i.e. execute those functions in parallel instead of sequential. Then finally we'll explore how to execute a block of code lazily using coroutine. And if this term 'lazy' is new to you then don't worry, you will understand what it means when we will see its demo. So without wasting any more time, let's begin. So here, we have a very simple program. Let's go through each line of code one by one. This is a suspending function which returns a message in the form of String. Then we have another suspending function which returns another message in the form of String. Now, please note that in both functions we are using a delay of 1 second. We are basically pretending to do some work for 1 second. Fine? Then we have the main function, and on our main function, we are using runBlocking coroutine builder. Which means our entire main function now executes within runBlocking coroutine. Fine? Here our main program starts and then it ends here. I guess no doubt till now. Now let us call these two functions from our main function. So here I will call getMessageOne function and store the returned value within a variable. Like this. Similarly, I will call getMessageTwo function and store the returned value within another variable. Great. And then I will print the entire message by joining them. Let us run the program. So here we go, the output is. as expected. But what is worth to consider is how these two functions are being executed. Are they getting executed in sequence? Or, are they getting executed concurrently? Well, we can easily know that by checking how much time is elapsed while executing these two functions. For that, I will use measureTimeMillis function. Which belongs to this package. Now, this function is going to measure the time taken by this code to execute. And we will get the time in milliseconds in this time variable. So once we get the time, we can print it. Like this. Nice and simple! Let us run our program. So here we go, it took 2 seconds to execute the two functions. which means 1 second was consumed here, and another second was consumed here. Which means these two functions executed one after another in sequence. i.e. this took one second, and this took another 1 second. So that is why in output we got 2 seconds altogether. So here you can note one thing. Within a coroutine which in our case is runBlocking, by default the methods are executed sequentially. So always remember this, if somebody asks you how the methods are executed within a coroutine then without any hesitation just say, it executes by default sequentially. Fine? So now we have seen the sequential execution, let us move ahead and see how we can make some arrangements to execute those functions concurrently. For beginners, who don't know what concurrent means, well, in simple words you can assume concurrent means parallel. Fine? So here, as mentioned these two statements are getting executed sequentially. Now, if we wrap these two functions within async or launch coroutine builders, then let's see what happens. What I am trying to say is: if we put async over here. And also here. Then we all know that this async is going to return the String object in the form of Deferred generic type object. So on the left let's use the Deferred type to avoid any confusion. And to extract the String value from this variable, we need to use await function. If you remember from the previous videos. So let's use await over here and also here. Let us run the program. So here we go the output remains almost the same. The only difference you will notice is in the time taken to execute these two functions. Right now it takes only 1 second to execute these functions. So let me explain to you, what exactly is happening? Well, this async function is a coroutine builder. It creates another coroutine that runs in the background. Similarly, this async again creates a background coroutine. And these two coroutines runs in the background at the same time, i.e. in parallel. So using async we have achieved concurrency. Fine? So this is how we achieve concurrency, among suspending functions by wrapping them within async coroutine builders within a parent coroutine builder . which in our case was runBlocking. Fine? Now also, you can get the same result using launch coroutine builder. But since we are returning a value that we need to use in our program, that is why in our case, we can use only async. But do remember we can achieve concurrency using the launch coroutine builder as well. Nice and simple! Also, within this async, you can put your other code as well. Because this is a coroutine and within a coroutine, you can put as many lines of code as you wish to as per your requirement. Don't forget that. So let us move on to our next topic of discussion. i.e. lazily execute the coroutine. Let's see how to do it. Now, before we start, let us do some changes to our program. Basically, let us simplify our code a little bit. Also, for this demo, we won't care about the time consumed by our code. So let's remove everything related to measure time. Then in our suspend functions, Let us add a print statement. So that we can know, these functions are getting executed. Now coming back to our main function. Now, what we are receiving as a result in these two variables, we are using them over here, in our print statements. Right? But if we comment on this print statement. then executing these two child coroutines are of no use. Because we are not using the returned result in our program. Right? But if you run the program Then you will see that the suspending functions are getting executed. Which is evident from these two print statements. So basically the suspending functions are getting executed and wasting system resources without giving any fruitful result in our application. So to avoid this, in Kotlin, we have a workaround for that. We can make our coroutine execute only if we use the result in our program. For that, as a parameter, just pass, start equal to CoroutineStart.LAZY And here as well do the same thing. If you run the program now, you will find that now those two suspending functions were not executed. Just because we are not yet using the returned result. In short, only if you use these values in your program, your coroutine is going to execute these functions. Fine? So now, if we comment out this statement. And run the program, then we get the output accordingly. Great isn't it? So in short, when this msgOne.await is executed, then only it starts your async coroutine. Similarly, when this msgTwo.await is executed, then only it starts to execute this async coroutine. Thus we write a code which is quite optimised. Nice and simple! So I hope you get an idea of what is meant by lazily starting a coroutine in Kotlin. So yes that's all for this topic. So in this way we have reached the end of this chapter. So in this chapter we basically learnt about how to compose suspending functions and execute them. So firsly we saw how code within the coroutine are sequential by default and to achieve concurrency within a Coroutine you can either use async or launch functions as a child coroutine builders. And finally we saw how to lazily start a Coroutine using async function and therefore optimise your code. So yes that is it for this chapter. In the next chapter we will explore CoroutineScope, CoroutineContext, and Dispatchers. And trust me these are the very sophisticated topics of Coroutines which many developers get confused upon. So let's jump on to our last and final chapter i.e. chapter 5. Hi, again this is Sriyank Siddhartha and let's start this chapter 5 with great energy and enthusiasm. I am totally excited for this last chapter. Are you? Now, the topic of CoroutineContext and Dispatchers is something which is like a nightmare for every developer. So I will try to answer all your small and big questions. So stay with me until the end of the video. Let's start with CoroutineScope. What does it mean actually? Well, we all know that launch function is a coroutine builder. It creates a coroutine. Now, when it creates a coroutine, then by default it gets attached to a special instance of CoroutineScope. So within the lambda expression if you use this keyword, then basically you will get access to the CoroutineScope instance. So in short, every coroutine has its own CoroutineScope instance attached to it. And this is something you need to remember. Similarly, the coroutine builders like async and runBlocking, also has a CoroutineScope object attached to it. Fine? Here we have runBlocking coroutine builder at the root level of the main function. So the IntelliJ IDE is showing us a hint, that within the lambda if you use 'this' keyword then you will be able to access the CoroutineScope object. So if you print this keyword, using a print statement. Then let's see what happens. So this entire output represents the CoroutineScope object. Also, the signature of CoroutineScope shows what kind of coroutine was created. It's a blocking coroutine since it was created by runBlocking function. ‘Active’ shows when the print statement was executed, the coroutine was active and then we have hash code printed in the form of HEX value. basically, this hashcode represents the uniqueness of the object. Fine? Now similarly, let's use launch and async coroutine builders and print the CoroutineScope objects. Let's run the program. So here is the output, The launch creates a Standalone Coroutine, and this async creates a Deferred Coroutine, which returns a deferred job object. Great isn't it? So basically the CoroutineScope represents what kind of coroutine you have created. Quite simple isn't it? Now, what about the CoroutineScope of the child coroutine. So here within this launch coroutine, if you add a child coroutine. Like this. And run the program. Then the child coroutine as well has its own CoroutineScope. You can see the parent CoroutineScope and child CoroutineScope are different. So just remember, every coroutine, irrespective of being a parent or a child, has its unique CoroutineScope. Nice and Simple! Now, moving on, we have CoroutineContext. Well, this topic is going to be a bit tricky, but don't worry we will tackle it in our own way. Well, similar to CoroutineScope, every coroutine has its own CoroutineContext. But with a twist. As mentioned, the CoroutineScope is unique for each Coroutine. right? But CoroutineContext can be inherited from parent to child. Meaning, the child coroutine can inherit the properties of the parent coroutine. Now, this CoroutineContext has basically two major components. Such as a Dispatcher, and a Job object. This Dispatcher is very important. It is the Dispatcher which decides on which thread the coroutine will execute. So please note this, very important. And you are already familiar with what this job object means and how using this job object you can control your Coroutine. I hope you remember this from the previous videos. And, apart from these two, we can also assign a name to the Coroutine. Fine? Let's understand things better in a demo. Now, here we already have some code which you can get from the link in the description. But for the next few minutes, I would suggest just focus on what I am saying? Don't worry about the code, you can anyways get the code from the GitHub link in the description. Well, just now we talked about CoroutineScope. Right? How with every coroutine there exist a CoroutineScope which is unique in nature. So similar to CoroutineScope, with every coroutine there exist a CoroutineContext. And within this coroutine, if you want to access this CoroutineScope then you can use 'this' keyword. Similarly, if you want to access CoroutineContext, then you can use a property of coroutineContext Fine? So let's document it. Great. Now, let us see how CoroutineContext play role in determining the thread for each coroutine. Let us start with a Coroutine without parameter. This is also known as CONFINED Coroutine. Now, when you create a coroutine without any parameter. then it will inherit the CoroutineContext form the immediate parent. i.e. this coroutine will inherit the CoroutineContext from its immediate parent which is this runBlocking coroutine right? And since this runBlocking coroutine executes on the main thread. So this child coroutine without any parameter will also execute in the main thread. To prove my point, let's use a print statement. Run the program. So yes, coroutine C1 runs on the main thread. Great isn't it. Next, we have coroutine with a parameter, such as Dispatchers.Default So if you use, Dispatchers.Default Like this. Then this will create a coroutine whose properties will be exactly the same as the coroutine created by GlobalScope.launch function. i.e. this will create a coroutine at the application level. And hence it will execute on a separate background thread. I hope you remembered this. Anyways, let's check the thread name. Run the program. So here, we go. It executes on a separate background thread. Great isn't it? Now, please note that it is the Dispatcher which determines on which thread your coroutine will execute. So in short, if you change the Dispatcher, then the thread on which your coroutine will operate will also get changed. Fine? Now, here let us add two more lines of code. Well, in case of GlobalScope.launch coroutine, if you remember in the very first video of this series, we explored that, suppose this statement gets executed in Thread T1, and after this, suppose a suspending function such as delay is executed then, in that case, the thread T1 gets released. And after delay, when this statement is executed, then it will either execute on Thread T1 or even it can execute on some other thread. Fine? So same is the case of Dispatchers.Default. After the delay, the next statement can change its thread. Let us run the program. So here Great. Moving on we have another Dispatcher. Such as Unconfined. Let's create a coroutine and add a print statement. So this coroutine which has Unconfined dispatcher will inherit the context from the immediate parent coroutine. Which is runBlocking in our case. So that is why this statement will execute on the same main thread. Fine? And if you add a delay function. and check the thread right after this. Then in that case this statement will be executed in a different thread. i.e. not on the same thread. Let us run the program and see the result. So here we go, the Thread C3 first executes on this thread. and after delay which is our suspending function, it executes on a different thread. Great isn't it? Let us quickly summarise what we learnt so far until now. The coroutine builder without parameter inherits the context from the immediate parent. Hence, the dispatcher, provides the same thread as that of the parent. Fine? and even after the execution of suspending function, the coroutine continues to execute in the same thread. In short, the coroutine remains confined to the same thread. and this is the reason, why we call such coroutine as CONFINED coroutine. Next, is Dispatchers.Default parameter. Such coroutine is exactly the same as GlobalScope.launch builder. They get their own context at the application level. So the dispatcher provides a separate background thread. Fine? And after the execution of suspending function, it might change its thread. So please note this. Then we have Dispatchers.Unconfined. Well, in this case, the context is inherited from the immediate parent. But after the execution of the suspending function, the coroutine executes in some other thread. So in short, the coroutine is not confined to just one thread. It can change its thread in future. So that is why such coroutine is also known as UNCONFINED coroutine. Fine? Next, let see one more way to create CoroutineContext. In this case, as a parameter, we can pass coroutineContext property. So this will pass the context of parent to the child. Fine? So if the parent runBlocking coroutine is getting executed in the main thread. Then this statement will also get executed in the main thread. And it actually behaves like a CONFINED coroutine. So after this delay, this statement will continue to execute in the main thread. Fine? Let us run the program. So here C4 main thread and after delay again C4 in the main thread. Great. Now, what if we cut the entire code from here, and paste it as a child of this C3 coroutine. So for this coroutine C4, the parent is this C3 coroutine. Right? and before this coroutine, this statement is being executed in, let us assume thread T1. Then in such a case, this child coroutine, where we are passing coroutineContext as a parameter, this statement will get executed in same thread T1. Fine? And also this statement will be executed in thread T1. Let us run the program. So here we go . the C3 got executed in this thread after delay, and after that, C4 got executed in the same thread how cool is that? So just now I showed you various ways in which coroutines get their context. Fine? And remember, it is the Dispatcher which decides what thread the coroutine will execute on. Nice and Simple! Now Dispatchers are basically of 4 types, first is Default, then we have Unconfined, then Main and then IO. Just now we saw these two dispatchers. Right? And this Main dispatcher basically works on the UI objects and this IO dispatcher is used for IO operations. and we will discuss these two dispatchers in a separate Android tutorial. Because it is in Android, where we will use UI components and do some IO operations. So for now don't worry much about them. So for the Dispatcher just remember it is the dispatcher which decide on which thread your coroutine will execute. Fine? Now, next, we have already explored this Job object in our previous chapters. So I guess no need to discuss anything related to this. Next, what about this Coroutine names. Well, you can assign a name to your coroutine and even combine two coroutine context together. And also by assigning names to your Coroutine, you can debug your coroutine. Right? I hope you had a wonderful journey watching this course. I am glad you have made it till the end of this course. So how was the course, please let me know in the comment box below. And please like this video, share this video and support my work in a way you can. This is Sriyannk Siddhartha signing off and thanks for watching and have a nice day. Bye!
Info
Channel: Smartherd
Views: 93,144
Rating: undefined out of 5
Keywords: smartherd, kotlin, coroutine tutorial for beginners, coroutine tutorial, coroutine advanced concepts, full coroutine course for free
Id: lmRzRKIsn1g
Channel Id: undefined
Length: 127min 37sec (7657 seconds)
Published: Tue Mar 01 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.