如何从 Service Android 调用挂起函数?

How to call suspend function from Service Android?

如何提供作用域或如何从服务中调用挂起函数Android? 通常,activity 或 viewmodel 为我们提供了范围,我们可以从那里启动暂停,但 Service

中没有类似的东西

您可以创建自己的 CoroutineScope with a SupervisorJob,您可以在 onDestroy() 方法中取消。只要您的服务被使用,使用此范围创建的协同程序就会存在。一旦您的服务 onDestroy() 被调用,所有以此范围启动的协程都将被取消。

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()
    }
}

编辑:将 Dispatchers.Main 更改为 Dispatchers.IO

SupervisorJob() (Kotlin GitHub) 是一个提供单向取消的作业;它允许取消传播 仅向下 .

The SupervisorJob ... is similar to a regular Job with the only exception that cancellation is propagated only downwards. [KotlinLang.org]

用例:您有一项服务可以创建日志条目、检查设置,并根据这些设置继续执行某些操作。例如,如果基于设置值的作业 运行 抛出异常,您是否希望取消父作业(范围)的所有子作业?如果不是(即你仍然希望你的日志记录和检查设置作业至少完成)那么你想使用 SupervisorJob(),甚至 supervisorScope (Kotlin GitHub) for 'scoped concurrency' [KotlinLang.org],因为两者都提供单向作业取消 - 并且在在这种情况下,提供的答案有效。

Coroutine Exception Handling - Supervision (KotlinLang.org)

但是,有一个更直接的解决方案可以回答这个问题。

要为您的服务提供 运行 协程(或暂停函数)执行阻塞代码的范围,您只需创建一个新的 CoroutineScope() with an EmptyCoroutineContext:

(来自 CoroutineScope 文档的片段)

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()
    }
}

我就是这样工作的

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()
    }
}