当包含它的服务停止时,协程不会停止

kha*_*our 4 java android kotlin foreground-service kotlin-coroutines

我有一个前台服务会延迟更改壁纸,因此我在其中使用协程,我使用 startService(Intent(this,MySerivce::class.java)) 从另一个类调用它,但是当我使用 stopService 停止它时(Intent(this,MySerivce::class.java)),仅在主线程停止时起作用(如 showNotification()),这是我的代码:

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val externalStorageState = Environment.getExternalStorageState()
    if (externalStorageState.equals(Environment.MEDIA_MOUNTED)){


    val root=getExternalFilesDir(null)?.absolutePath
        val myDir = File("$root/saved_images")
        val list = myDir.listFiles()
        if (myDir.exists()&&list.size>=2){
            CoroutineScope(Dispatchers.IO).launch {
                val time = intent?.getIntExtra("TIME",0)
                if (time != null) {
                    manageWallpapers(list,time)
                }

            }
        }}

    
    showNotification()
    
    return START_STICKY
}
}
Run Code Online (Sandbox Code Playgroud)

这是管理壁纸功能

private suspend fun manageWallpapers(list: Array<File>?, time:Int){

    while (true){
        if (list != null) {
            for (image in list){

                setWallpaper(image)
                delay(time.toLong())
                
            }
        }

    }

    
}
Run Code Online (Sandbox Code Playgroud)

Fra*_*esc 6

您需要保留对返回的作业的引用launch,并cancel()在服务停止时调用它。

private var job: Job? = null

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val externalStorageState = Environment.getExternalStorageState()
    if (externalStorageState.equals(Environment.MEDIA_MOUNTED)){


    val root=getExternalFilesDir(null)?.absolutePath
        val myDir = File("$root/saved_images")
        val list = myDir.listFiles()
        if (myDir.exists()&&list.size>=2){
            job = CoroutineScope(Dispatchers.IO).launch {   // HERE
                val time = intent?.getIntExtra("TIME",0)
                if (time != null) {
                    manageWallpapers(list,time)
                }

            }
        }}

    
    showNotification()
    
    return START_STICKY
}
}

override fun onDestroy() {
    job?.cancel()
    job = null
    super.onDestroy()
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是保留对您的引用CoroutineScope并进行调用cancel


Ten*_*r04 5

如果您从 LifecycleService 子类化,则可以使用lifecycleScope它来启动协程,因此当服务停止时它将自动取消。

build.gradle

implementation 'androidx.lifecycle:lifecycle-service:2.3.1'
Run Code Online (Sandbox Code Playgroud)

在您的服务中,以下子类LifecycleService

lifecycleScope.launch {
    val time = intent?.getIntExtra("TIME",0)
    if (time != null) {
        manageWallpapers(list,time)
    }
}
Run Code Online (Sandbox Code Playgroud)

无需指定 Dispatchers.IO,因为您仅调用挂起函数,而不是阻塞函数。