 Okay, everyone, thank you for coming. Yeah, again, if you leave the room, please help your chair, because it's really noisy otherwise. Also, we still have three licenses, because actually one got... Yeah, someone won it. So, quick recall that you can open a pull request and send it to me and you basically get a license. Now it's time to introduce, again, Geoffrey, that is going to talk about improving your Android app with Coroutines. So, please welcome him. So, hello, again, for some of you. Do you hear me correctly? Okay, good. So, I'll talk to you about Coroutines again. So, once more, I'm a video line member and I work at Video Labs, which is a company dedicated to people full-time on VLC development. I do the VLS Android adaptation. First of all, in Android, we have a callback-based API, mostly, and the catch of Coroutines, if you had the basic this morning, is that we just trade some blocking operation for, like, callback-hidden stuff. So, we dispatch our code like we use on Android, for example, when we post a runnable in a thread. So, the function is not a call stack anymore. Execution is not immediate. So, the catch here on Android is that we have to keep in mind that the dispatch is very important and we cannot respect the UI state. We cannot assume what the UI state is. For example, here, I just show you the run on UI thread, which is a convenient method on Java. You have the equivalent with Coroutines, which is basically just launch. This will dispatch, except if you precise that you don't want this initial dispatch and the code will be executed immediately until it suspends, of course. For example, here we are in the uncreated callback and we launch a Coroutine. So, I print something at every step and you can read that it prints that we are in uncreated. We end the uncreated before the Coroutine starts. We even print on-start, so we go to the on-start state before this code in the launch is executed and then we have our Coroutine running. So, just be aware that if you launch a Coroutine, like let's say in uncreated, it will effectively execute once the app is already created and possibly once the activity is destroyed. Maybe user will just launch the UI in landscape mode and you have a screen rotation executing so the activity can be instantly destroyed before your Coroutine executes. Fortunately for us, there is the Coroutine scope to help implement a structured concurrency which will allow us to map the... to map our Coroutine's life with the Android life cycles. So, first of all, we use the scope like an object. It's just a container for the Coroutine context, the default one, and it will also host a parent job which we can use to just cancel every job once we are done with the view. Here I show you the basics again. So, launch is usually the entry point of a Coroutine. It returns a job. So, if you want to have a conceivable stuff, you can just use the launch inside another Coroutine and cancel it at will. There is the with-context call. With context, you can precise a context. Here I just tell that I want to execute it with the dispatcher.io, which is an IO thread pool to get an image. So, we access fires. We want this to be executed in the thread pool. And in the meantime, the main thread is free. So, the Coroutine is suspended, which means that the main thread is free for other operations. Your app continues its life. And you'll get back to it once the job is ready. The image is fetched and the bitmap is ready to be executed. So, we come back to the main thread once it's available and we can fill our image view. There is also a Coroutine scope function, which is very like the with-context. With-context actually is a new Coroutine scope in our country scope in the current one. And the Coroutine scope awaits for all its children to be over. So, in this example, I used the async call to launch two parallel jobs and use the result as soon as both have completed. And this Coroutine scope call is just suspending until all operations are over. Exactly like with-context. Because this is, again, the same thing. With-context has some shortcuts if we already are in the correct context. But basically that's it. So, the most convenient thing here is the Coroutine scope matching our lifecycle and Android X, especially the KTX extension, now provide a usual extension function. We are ready to use lifecycle scope in activity now. We just have to use it. It will initiate a Coroutine scope and this scope will be canceled when the activity is destroyed. So, for any Coroutine job you have to do, just use this scope and it will do this creation and cancellation for you. So, in this launch, for example, I'm sure this code will be executed once the activity is still alive. If I fetch a file in the background thread and I come back when the activity is dead, is destroyed, this Coroutine won't resume. So, the file has been fetched, but we won't use it. It just will be dropped. We don't come back in the main thread if the scope is canceled. There is the equivalent for view model, which is much more useful because usually you want to execute your Coroutine view models. It survives the screen rotation, for example. So, it's recommended to use it. This is view model scope. Very interesting. Once the view model is clear, the scope is canceled, all your jobs are canceled and you don't have to... If you implemented it correctly, this is automagic. This is how you implement a Coroutine scope if you ever needed to do that for another object, another lifecycle, another session, let's say. You can either create a Coroutine scope object or your class can implement the Coroutine scope interface. You just have to override the value Coroutine context, which will just... Here be like we want to work in the main thread, so use dispatchers.main and we add a supervisor job to just control all our children's Coroutines and consider them once we're done. And then, whenever your object is clear and you cancel the Coroutines scope, you have a cancel function. Here is the actual implementation of this function. It's just called the job in the context and console it. So, this is the parent job of all your Coroutines. A nice addition really recent in Android X is when started, it's a with context call with a custom dispatcher. And this dispatcher will be at a queue for a job and will be paused whenever the, let's say, your activity or your lifecycle owner is not on started state. So, your activity comes in background. Your Coroutine won't resume. So, it's from a background task. The result is ready, it's stored, but it won't execute. And once the activity is started again, we will do this resume and use the result. And, of course, this will be cancelled too if the activity is destroyed. There is a convenience when started function which just wrap this with context with this one starting in a launch call. So, you don't have to already be in a Coroutine to start some job. Today, most of the libraries support suspend function. I showed the retrofit example this morning. You can now just define your retrofit function as suspend and you have the correct result. This is the very same thing for Ruby. Instead of having a blocking function or just wanting to, you can have like a live data of your result which is extremely unfun on Android, but you also can declare it as a suspend function which will return the type you want. So, this will suspend during the background work and you come back on main thread with your result. You also can get a flow and just consume your flow and room will emit in this flow every time your data is updated. So, that's three different ways to just wait for your result and safely manage it in main thread. You have some transformation available. Here is the simple implementation. I just use a mediator live data which is a live data subscribing another one to expose its result and in the meantime, you can do some transformation. And I use the launch call to execute in a Coroutine some work and want to offload, let's say. And Android KTX now has some extension function like map which does exactly that. So, you have some switch map and some transformation really with simple content extension function and you can do some Coroutine job on it. There is the reverse approach also. You can create a live data within a Coroutine scope doing some suspending function and posting its value when it's ready. So, here we have a very simple one. We just emit a low every second. So, the idea is to do live data which is almost like a flow. So, this is suspending. You can do IO in it, anything you want with context or anything and emit in a live data really easily now. It's in live data, lifecycle live data KTX starting version 2.2. So, and then you just have to observe this and get the result on your UI. Now, for a complete different use case, you have Actors on CodeLinux. This will probably be either replaced or enriched for a final API. But this is very like a handler except that this handler is executed in a Coroutine scope and you can do some suspending functions. So, you will queue some suspending calls and you can do what we call like confined mutability. So, here I do some like modification and deletion and also read access on my dataset. So, if I do all of this through my actor, I am guaranteed that all operation will execute once, one after the other. So, I never have any concurrent access on it. So, I don't need any lock. I don't need to block any thread. You just be queued. And to use it, I'll just, here I offer to the thread. So, it's a completely, I think it doesn't suspend. You just offer and in my case, I chose a limited capacity. So, the offer will always accept until this actor is closed. And this actor will automatically close once the lifecycle is canceled also. So, always the same idea with structured concurrency. So, this actor will leave as long as the current Coroutine scope. So, I'll just like offer to this actor any operation I want to do, they will be queued. They will execute and you can do any suspending function, calculation, IO access, et cetera. This has been really useful, repository layer of VLC to do some complicated operation like any modification also. And expose it, then expose it to the UI. So, if you have a reactive architecture, so if you use live data a lot, you just basically, UI will just observe the results. So, you don't need synchronous results. Now, interesting part of Kotlin Coroutines are the callback L wrapping. We just, we can hide all of these callbacks and get a simple function to get the result and suspend in the meantime. And suspend until the callbacks are called. So, here this is the libvrc fibrosing asynchronous API. So, we basically request to browse a certain URL and then we have callbacks to tell us that we discovered every media on the fly. And then, at the end, the browse is ended and all the discovery, all the folder has been discovered. So, first implementation was just, we add a list that we filled. We declared listener to get the callbacks, which will get it. The refresh function was just requesting this browsing and telling which listener will continue the job. And then in this job, we add to fill the list and basically expose it to the UI in the end. Now, we have flow. In this case, it's based on a channel, very like the actors. But this has the quality of being a call stream. So, we declare a flow and this will be executed only when someone will consume it, not before. So, this is declarative. So, write this code and this will not be executed immediately just whenever it's lazy. So, in this flow, we declare our listener and we offer our media to a channel because this is a callback flow, which is a channel flow. Under the hood, this is a channel working. So, in this one, we have our callbacks and this callback fill the channel and close it once we're done. And then we can request our browsing. The listener is ready and await the result to be ready. The usage of it is, first of all, the simplest operator is collect. So, for every new file we discovered, the collect will be and we can print the name. And this is suspending. We also have two-list operator which waits for the old files to be ready and we get the list. And we also can do some transformation because flow has matching, API matching, for example. So, we have, here is the map.null. So, we filter the null element and then on the null one, we can do our transformation and continue to expose it. This is how we wrap callbacks for a single-shot API. We, in this example, we just want to start the VLC media library and once it's ready, we want to query some media. So, I just write a higher-order function. We have a shortcut. If media library is already started, we just do our call. We don't need to suspend. But otherwise, we'll prepare a listener for the callback call when the library is ready and we start this library. Once it's ready, the continuation resumed. We resumed the coroutine. This is how we create the coroutine. And we're ready to execute. So, this function can be cancelled. Cancelable too. We have an additional call to do. And so, for, if we connect, the current scope is cancelled, we properly remove the listener we add and we don't wait for the result. And the usage is extremely simple. We just swap our media library call in this function. And we have automatically a suspending function which waits for the media library to be ready and then queries it. Another fun one is using flow for events. I guess you saw that this morning. I'm still working with the channel. So, we do a channel. We consume it as a flow. And basically, this is for a recycler view adapter. So, every click of element or long click is sent to this channel. And this channel is transformed as a flow. And then, on the fragment side, we just collect this flow to get the click events. So, it's pretty simple. On each, and we process it. So, we have a click sealed class. And then, we launch in life cycle scope to be in our UI scope. And then, this is the extension function of click process. We have the simple click, long click operation, et cetera. That's fairly easy to use. So, just we consume a flow and we just declare how we will do it. And that's a very clean way to pass events from your adapter to your fragments, for example. That's it for me for today. For Android X, I hope you will handle it. And very, very well. Hi, there are questions. We're starting a new Android project. And we are currently having problems with the debugging. Do you have any tips about how can we debug such complex coroutines? Debugging the code? Yeah. So, you want some tips for debugging the coroutine, right? Judge Vance tries to make this work easier and the debugger, which is better and better to follow these calls. The stack trace are more respectful of the real call stack now, in most cases. Also, I didn't tell you in this talk, but when you define a coroutine context, you can give it a name. This is just a string to add. I don't have any example, but let's say in the with context you say you have the dispatcher.io. You can just add the plus operator to pass it a string. And this is the name of your coroutine. Any other question? Thank you very much.