How to provide scope or how to call suspend function from Service Android? Usually, activity or viewmodel provides us the scope, from where we can launch suspend but there is no similar thing in Service
You can create your own CoroutineScope
with a SupervisorJob
that you can cancel in the onDestroy()
method. The coroutines created with this scope will live as long as your Service is being used. Once onDestroy()
of your service is called, all coroutines started with this scope will be cancelled.
class YourService : Service() {
private val job = SupervisorJob()
private val scope = CoroutineScope(Dispatchers.IO + job)
...
fun foo() {
scope.launch {
// Call your suspend function
}
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
}
Edit: Changed Dispatchers.Main
to Dispatchers.IO
job.cancel()
by job.cancelChildren()
at onDestroy
because if your service is shown multiple time only the first coroutine will work. –
Lunde for me worked like that
import androidx.lifecycle.lifecycleScope
class ServiceLife : LifecycleService() {
private var supervisorJob = SupervisorJob(parent = null)
override fun onCreate() {
super.onCreate()
val serviceJob = lifecycleScope.launch {
//some suspend fun
}
supervisorJob[serviceJob.key]
supervisorJob.cancel()
}
}
SupervisorJob()
(Kotlin GitHub) is a job that provides uniderectional cancellation; it allows for cancellations to propogate downwards only.
The SupervisorJob ... is similar to a regular Job with the only exception that cancellation is propagated only downwards. [KotlinLang.org]
Use case: You have a service that makes a log entry, checks settings, and depending on those settings goes ahead and performs some actions. Do you want all children jobs of the parent job (scope) to cancel if, for instance, a job run based on settings' values throws an exception? If not (i.e. you still want your logging and check for settings jobs to complete at the least) then you want to use the SupervisorJob()
, or even supervisorScope
(Kotlin GitHub) for 'scoped concurrency' [KotlinLang.org], as both provide unidirectional job cancellation - and in that case the provided answer works.
Coroutine Exception Handling - Supervision (KotlinLang.org)
However, there is a more direct solution that answers the question.
To provide to your service a scope with which to run coroutines (or suspending functions) that execute blocking code, you can simply create a new CoroutineScope()
with an EmptyCoroutineContext
:
(Snippet from CoroutineScope Documentation)
If the given context does not contain a Job element, then a default
Job()
is created. This way, cancellation or failure of any child coroutine in this scope cancels all the other children, just like inside coroutineScope block [Kotlin GitHub]
class YourClass : Extended() {
...
private val serviceScope: CoroutineScope( EmptyCoroutineContext )
...
private inner class ServiceHandler( looper: Looper ): Handler( looper ) {
override fun handleMessage( msg: Message ) {
super.handleMessage( msg )
serviceScope.launch {
try{
+ ...
} catch( e: Exception ) {
+ ...
} finally {
stopSelf( msg.arg1 )
}
}
}
}
override fun onCreate(){
+ ...
}
override fun onDestroy(){
/* In a service, unlike in an activity, we do not
need to make a call to the super implementation */
//super.onDestory()
serviceScope.cancel()
}
}
Alternatively, you can extend LifecycleService
rather than Service
on your class. This will provide you access to lifecycleScope
in your service, just like in an Activity or Fragment.
© 2022 - 2024 — McMap. All rights reserved.