Johann Pardanaud
01/06/2022, 9:57 AMprivate class HelloWorldService : GreeterGrpcKt.GreeterCoroutineImplBase() {
override suspend fun sayHello(request: HelloRequest) = helloReply {}
}
And I want to write the following code at the beginning of this method (from Kotlin's documentation):
launch {
delay(1000L)
println("World!")
}
println("Hello")
If I simply copy-paste this code in my method, launch
isn't recognized as a valid method because it should by used on a coroutine scope.
If I wrap my code with a coroutineScope
like this:
override suspend fun sayHello(request: HelloRequest) = coroutineScope {
launch {
delay(1000L)
println("World!")
}
println("Hello")
helloReply {}
}
It builds, the code is even executed when I make a call from the client, however the server returns an UNKNOWN
code before the launch
job can even finish and the HelloReply
is not used.
So I think I shouldn't create my own coroutine scope and I should use a scope already defined by the server, but I don't find anything related to a "default gRPC coroutine scope" in the API reference.
I must be missing something really obvious, can someone help me run this really basic code please? 🙏Alexandre Brown
01/08/2022, 7:23 PMoverride val coroutineContext = Dispatchers.Default
inside your constructor.
Then you'll be able to use launch(coroutineContext) { }
Johann Pardanaud
01/10/2022, 3:52 PMJoffrey
01/11/2022, 9:52 AMCoroutineScope
is a discouraged approach now. When you need custom scopes, it's preferred to just declare a private property of type CoroutineScope
instead of implementing the interface (and don't forget to cancel it according to the lifecycle of your class)Johann Pardanaud
01/11/2022, 10:08 AMoverride suspend fun sayHello(request: HelloRequest) = coroutineScope {
launch(context) {
delay(1000L)
println("World!")
}
println("Hello")
helloReply {}
}
The difference with my original code is launch(context) {
instead of launch {
Alexandre Brown
01/11/2022, 11:53 AMJoffrey
01/11/2022, 12:00 PMManual implementation of this interface is not recommended, implementation by delegation should be preferred instead.
At least for public classes, implementing the interface breaks the single-responsibility principle. Also, with the introduction of the CoroutineScope() factory function it is less boilerplate to just call the factory and assign a property. This article also describes a bit the "why not implement it": https://proandroiddev.com/why-your-class-probably-shouldnt-implement-coroutinescope-eb34f722e510 If that's any hint, Android also uses the property approach with the built-inshould be declared as a property on entities with a well-defined lifecycle that are responsible for launching children coroutines.CoroutineScope
viewModelScope
and lifecycleScope
.Alexandre Brown
01/11/2022, 9:48 PM