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!