Kotlin 使いには、CoroutineWorker がとても便利なのです.
Workerがキャンセルされたときに後始末をしたかったので、onStopped() でやればいーやと思ったのですが、
final がついているので override できませんでした(泣)
なぜ final になっているかというと、内部で確実にCoroutine を停止するためでした。
CoroutineWorker
public final override fun onStopped() {
super.onStopped()
future.cancel(false)
}
Workerがキャンセルされたときの後始末をおこなう、実装サンプルです。
sample.kt
package sample
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import androidx.work.*
import java.util.*
class MyWorker(val context: Context, params: WorkerParameters) :
CoroutineWorker(context, params) {
override suspend fun doWork(): Result {
runCatching {
return workSomething()
}.onFailure { throwable ->
// Worker が キャンセルされると
// kotlinx.coroutines.CancellationException が発生する
// (実態は JobCancellationException)
cleanup()
}
return Result.success()
}
private fun workSomething(): Result {
// ...
return Result.success()
}
private fun cleanup(): Result {
// 後始末をする処理
// ...
return Result.success()
}
}
var workerId: UUID? = null
fun startWorker(context: Context) {
val manager = WorkManager.getInstance(context)
workerId?.let {
// Worker が動いているかチェック
val isRunning = manager.getWorkInfoById(it).get().state == WorkInfo.State.RUNNING
if (isRunning) {
// Worker をキャンセルする
manager.cancelWorkById(it)
return
}
}
val myWorker: WorkRequest = OneTimeWorkRequestBuilder<MyWorker>()
.setInputData(workDataOf())
.build()
workerId = myWorker.id
// worker を起動する
manager.enqueue(myWorker)
}