如何将不同的作品安排为一个独特的作品?

How to schedule different works as a unique work?

所以我用这些工作表示替换了我所有的工作。

我在重构的当前状态下有两个问题。

我有很多工人 类,假设这些是 W1,W2,W3...

我的问题是,当我将工作安排为按时和定期时。我将 uniq 与 uniq 标签一起使用。我的问题是,当我使用“W1_TAG”标签将 W1 作为周期性队列排队,然后我想从具有相同标签的 W1 创建一个 onTime 时,它​​不会启动,因为有另一个 Work with同一个标签。

我想实现的是,如果我启动 W1 worker,然后以周期性方式启动 W2 worker,然后以 onTime 方式启动 W2,则操作如下:

-W1开始 -W2 定期看到,W1 运行s,所以他会等到 w1 成功 -w2 onTime 看到,还有一个W2(周期性的无所谓),他会被移除吗?由 WorkManager,所以 w2 周期性保持并且 w2 准时不会 运行

我知道有一个 enqueUniqWork 的可能性,但它只追加或保留之前的工作人员,这不是工作不同的标签。

所以目前我通过添加不同的标签解决了这个问题,但我想知道,我能用同样的方法解决这个问题吗?

工作安排

        fun schedulePeriodicAsync(context: Context) {
            val constraint =
                Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED).build()

            val data = Data.Builder()
            data.putBoolean(IS_PERIODIC_KEY, true)

            val sendCertificatesWorker =
                PeriodicWorkRequest.Builder(
                    SendCertificatesWorker::class.java, 900000, TimeUnit.MICROSECONDS
                )
                    .setConstraints(constraint)
                    .setInputData(data.build())
                    .setBackoffCriteria(
                        BackoffPolicy.LINEAR,
                        OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                        TimeUnit.MILLISECONDS
                    ).build()

            WorkManager.getInstance(context).enqueueUniquePeriodicWork(
                TAG,
                ExistingPeriodicWorkPolicy.KEEP, sendCertificatesWorker
            )
        }

        fun scheduleNowAsync(context: Context, workCallback: JobCallback? = null) {
            jobCallback = workCallback

            val constraint =
                Constraints.Builder()
                    .setRequiredNetworkType(NetworkType.CONNECTED).build()

            val data = Data.Builder()
            data.putBoolean(IS_PERIODIC_KEY, false)

            val sendCertificatesWorker =
                OneTimeWorkRequest.Builder(SendCertificatesWorker::class.java)
                    .setConstraints(constraint)
                    .setInputData(data.build())
                    .setBackoffCriteria(
                        BackoffPolicy.LINEAR,
                        OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                        TimeUnit.MILLISECONDS
                    )
                    .build()

            WorkManager.getInstance(context).enqueueUniqueWork(
                TAG_NOW,
                ExistingWorkPolicy.KEEP, sendCertificatesWorker
            )
        }

Worker class:
class SyncPricesWorker(
    val healthCheckApi: HealthCheckApi,
    val synchronizer: Synchronizer,
    val sharedPreferences: SharedPreferences,
    private val context: Context,
    workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams) {

    override suspend fun doWork(): Result {
        Timber.d("SyncWorker starts")
        var workResult = Result.success()
        
        if (runAttemptCount >= 3) {
            return Result.failure()
        }

        workCallback?.jobStart()

        withContext(Dispatchers.IO){
            Timber.d("SyncWorker middle")
            try {
                healthCheckApi.checkHealth(ApiModule.API_KEY).await()

                synchronizer.sendInvoices()
            } catch (e: Exception) {
                workCallback?.jobEnd()

                workResult = Result.retry()
            }
        }

        if (workResult == Result.success()) {

            workCallback?.jobEnd()

            sharedPreferences.edit().putLong(ApiParameters.KEY_LATEST_PRODUCT_PRICE_SYNC_DATE, Date().time).apply()
        }

        Timber.d("SyncWorker end")
        return workResult
    }

Synchronization class method:
    suspend fun sendInvoices(invoiceHeaderIdToSend: String? = null): SendResult {
        val asd = invoiceRepository.getInvoicesWithStatus(0, invoiceHeaderIdToSend ?: "")
        if (asd.isEmpty()) return SendResult.success(10)

        val asd2 = salesApi.sendInvoices(asd).await()
        return if (asd2.isSuccessful) {
            val invoicesList = arrayListOf<InvoiceHeader>()
            invoicesList.addAll(asd)

            invoicesList.forEach { it.status = Constants.STATUS_SENT.code }

            invoiceRepository.updateInvoiceHeaders(invoicesList)
            SendResult.success(asd.size)
        } else {
            Timber.tag("sendInvoices").e(asd2.errorBody()?.string().toString())
            SendResult.error(asd.size, asd2.errorBody()?.string().toString())
        }
    }

WorkManager's TAG are properties of your WorkRequest, that you set using addTag()WorkRequest.Builder:

val sendCertificatesWorker =
        PeriodicWorkRequest.Builder(
           SendCertificatesWorker::class.java, 900000, TimeUnit.MICROSECONDS
        )
                           .setConstraints(constraint)
                           .setInputData(data.build())
                           .setBackoffCriteria(
                               BackoffPolicy.LINEAR,
                               OneTimeWorkRequest.MIN_BACKOFF_MILLIS,
                               TimeUnit.MILLISECONDS
                            )
                           .addTag(TAG) // <- ADDING A TAG
                           .build()

当您将独特的作品加入队列时,you're using a uniqueName to identify that unique work

WorkManager.getInstance(context).enqueueUniqueWork(
        UNIQUE_NAME_NOW,
        ExistingWorkPolicy.KEEP, sendCertificatesWorker
    )

也就是说,WorkManager 允许为 OneTimeWorkers 设置 chain of workers,但不允许为 PeriodicWorkers 设置

在我看来,实现你想要的最好的选择是在 W2 的开始添加一些控件来检查 oneTimeWorkers (using unique TAGs) 的状态,并在那里应用你需要的逻辑以达到您想要的结果。

如果你想覆盖 W2 Periodic 已经是 运行 的情况,你需要注意一下,然后启动 OneTime W1。在这种情况下,或者你 cancel Periodic W2 from W1 (and handle cancellation 在 W2) 或者你可能同时得到 W1 和 W2 运行。